#!/bin/sh

# Copyright (c) 2021-2025 刘富频
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#     https://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.


# last line mode :set foldmethod=marker
# command mode zM  fold close all
# command mode zR  fold open all

# {{{ coding convention

# 1. The variable/function name starts with underscore "_" means that it is a private variable/function.
# 2. 0 represents the boolean value false
# 3. 1 represents the boolean value true

# }}}
##############################################################################
# {{{ utils

COLOR_RED='\033[0;31m'          # Red
COLOR_GREEN='\033[0;32m'        # Green
COLOR_YELLOW='\033[0;33m'       # Yellow
COLOR_BLUE='\033[0;94m'         # Blue
COLOR_PURPLE='\033[0;35m'       # Purple
COLOR_OFF='\033[0m'             # Reset

print() {
    printf '%b' "$*"
}

echo() {
    printf '%b\n' "$*"
}

note() {
    printf '%b\n' "${COLOR_YELLOW}🔔  $*${COLOR_OFF}" >&2
}

warn() {
    printf '%b\n' "${COLOR_YELLOW}⚠️  $*${COLOR_OFF}" >&2
}

success() {
    printf '%b\n' "${COLOR_GREEN}✅️  $*${COLOR_OFF}" >&2
}

error() {
    printf '%b\n' "${COLOR_RED}💔  ndk-pkg: $*${COLOR_OFF}" >&2
}

abort() {
    EXIT_STATUS_CODE="$1"
    shift
    printf '%b\n' "${COLOR_RED}💔  ndk-pkg: $*${COLOR_OFF}" >&2
    exit "$EXIT_STATUS_CODE"
}

step() {
    STEP_NUM=$(expr ${STEP_NUM-0} + 1)
    STEP_MESSAGE="$*"
    printf '\n%b\n' "${COLOR_PURPLE}=>> STEP ${STEP_NUM} : ${STEP_MESSAGE} ${COLOR_OFF}"
}

run() {
    echo "${COLOR_PURPLE}==>${COLOR_OFF} ${COLOR_GREEN}$@${COLOR_OFF}"
    eval "$@"
}

list_size() {
    printf '%s\n' "$#"
}

isInteger() {
    case "${1#[+-]}" in
        (*[!0123456789]*) return 1 ;;
        ('')              return 1 ;;
        (*)               return 0 ;;
    esac
}

bppend_to_PATH() {
    case ":${PATH}:" in
        *:"$1":*) ;;
        *) export PATH="$1:$PATH" ;;
    esac
}

bppend_to_ACLOCAL_PATH() {
    case ":${ACLOCAL_PATH}:" in
        *:"$1":*) ;;
        *) export ACLOCAL_PATH="$1:$ACLOCAL_PATH" ;;
    esac
}

git() {
    if [ -z "$SSL_CERT_FILE" ] ; then
        command git "$@"
    else
        command git -c http.sslCAInfo="$SSL_CERT_FILE" "$@"
    fi
}

# git_checkout <URL> --ref-from=<FROM> --ref-to=<TO> --depth=<N> -B <CHECKOUT-BRANCH-NAME> -C <WORKDIR> --recursive
git_checkout() {
    OLDCWD="$PWD"

    unset GIT_FETCH_FROM_URL
    unset GIT_FETCH_FROM_REF
    unset GIT_FETCH_TO___REF
    unset GIT_FETCH_DEPTH
    unset GIT_FETCH_SUBMODULE_RECURSIVE
    unset GIT_CHECKOUT_BRANCH_NAME
    unset GIT_WORK_DIR

    if [ -z "$NDKPKG_URL_TRANSFORM" ] ; then
        GIT_FETCH_FROM_URL="$1"
    else
        GIT_FETCH_FROM_URL="$("$NDKPKG_URL_TRANSFORM" "$1")"
    fi

    shift

    while [ -n "$1" ]
    do
        case $1 in
            --ref-from=*)
                GIT_FETCH_FROM_REF="${1#*=}"
                ;;
            --ref-to=*)
                GIT_FETCH_TO___REF="${1#*=}"
                ;;
            --depth=*)
                GIT_FETCH_DEPTH="${1#*=}"
                ;;
            -B) shift
                GIT_CHECKOUT_BRANCH_NAME="${1#*=}"
                ;;
            -C) shift
                GIT_WORK_DIR="$1"
                ;;
            --recursive)
                GIT_FETCH_SUBMODULE_RECURSIVE=1
                ;;
        esac
        shift
    done

    [ -z "$GIT_FETCH_DEPTH" ] && GIT_FETCH_DEPTH=1
    [ -z "$GIT_FETCH_FROM_REF" ] && GIT_FETCH_FROM_REF='HEAD'
    [ -z "$GIT_FETCH_TO___REF" ] && GIT_FETCH_TO___REF='refs/remotes/origin/master'

    [ -z "$GIT_CHECKOUT_BRANCH_NAME" ] && GIT_CHECKOUT_BRANCH_NAME="${GIT_FETCH_TO___REF##*/}"

    if [    -n "$GIT_WORK_DIR" ] ; then
        [   -d "$GIT_WORK_DIR" ] || run install -d "$GIT_WORK_DIR"
        run cd "$GIT_WORK_DIR"
    fi

    run git -c init.defaultBranch=master init
    run git remote add origin "$GIT_FETCH_FROM_URL"
    run git -c protocol.version=2 fetch --progress --depth="$GIT_FETCH_DEPTH" origin "$GIT_FETCH_FROM_REF:$GIT_FETCH_TO___REF"
    run git checkout --progress --force -B "$GIT_CHECKOUT_BRANCH_NAME" "$GIT_FETCH_TO___REF"

    git_submodule_update_recursive

    run cd "$OLDCWD"
}

git_submodule_update_recursive() {
    if [ -z "$1" ] ; then
        GIT_REPO_ROOT_DIR="$PWD"
    else
        GIT_REPO_ROOT_DIR="$1"
    fi

    GIT_SUBMODULE_HAVE="$(cd "$GIT_REPO_ROOT_DIR" && find . -type f -name '.gitmodules' -print -quit)"

    if [ -n "$GIT_SUBMODULE_HAVE" ] ; then
        if [ -z "$NDKPKG_URL_TRANSFORM" ] ; then
            run git submodule update --init --recursive
        else
            unset GIT_SUBMODULE_BASEDIR_STACK

            GIT_SUBMODULE_CONFIG_FILE_LIST="$(find "$GIT_REPO_ROOT_DIR" -type f -name '.gitmodules')"

            for f in $GIT_SUBMODULE_CONFIG_FILE_LIST
            do
                if [ -z "$GIT_SUBMODULE_BASEDIR_STACK" ] ; then
                    GIT_SUBMODULE_BASEDIR_STACK="${f%/*}"
                else
                    GIT_SUBMODULE_BASEDIR_STACK="$GIT_SUBMODULE_BASEDIR_STACK;${f%/*}"
                fi
            done

            while [ -n "$GIT_SUBMODULE_BASEDIR_STACK" ]
            do
                case $GIT_SUBMODULE_BASEDIR_STACK in
                    *\;*) GIT_SUBMODULE_BASEDIR="${GIT_SUBMODULE_BASEDIR_STACK##*;}" ; GIT_SUBMODULE_BASEDIR_STACK="${GIT_SUBMODULE_BASEDIR_STACK%;*}" ;;
                    *)    GIT_SUBMODULE_BASEDIR="${GIT_SUBMODULE_BASEDIR_STACK}"     ; GIT_SUBMODULE_BASEDIR_STACK=
                esac

                run cd "$GIT_SUBMODULE_BASEDIR"

                GIT_SUBMODULE_NAME_LIST="$(sed -n '/\[submodule ".*"\]/p' .gitmodules | sed 's|\[submodule "\(.*\)"\]|\1|')"

                for GIT_SUBMODULE_NAME in $GIT_SUBMODULE_NAME_LIST
                do
                    GIT_SUBMODULE_PATH="$(git config --file=.gitmodules --get "submodule.$GIT_SUBMODULE_NAME.path")"
                    GIT_SUBMODULE_URL="$(git config --file=.gitmodules --get "submodule.$GIT_SUBMODULE_NAME.url")"
                    GIT_SUBMODULE_URI="$("$NDKPKG_URL_TRANSFORM" "$GIT_SUBMODULE_URL")"

                    run git submodule set-url "$GIT_SUBMODULE_PATH" "$GIT_SUBMODULE_URI"
                done

                run git submodule update --init

                GIT_SUBMODULE_PATH_LIST="$(git submodule | sed 's|^ *||' | cut -d ' ' -f2)"

                for GIT_SUBMODULE_PATH in $GIT_SUBMODULE_PATH_LIST
                do
                    GIT_SUBMODULE_CONFIG_FILE_LIST="$(find "$GIT_SUBMODULE_PATH" -type f -name '.gitmodules')"

                    for f in $GIT_SUBMODULE_CONFIG_FILE_LIST
                    do
                        if [ -z "$GIT_SUBMODULE_BASEDIR_STACK" ] ; then
                            GIT_SUBMODULE_BASEDIR_STACK="$GIT_SUBMODULE_BASEDIR/${f%/*}"
                        else
                            GIT_SUBMODULE_BASEDIR_STACK="$GIT_SUBMODULE_BASEDIR_STACK;$GIT_SUBMODULE_BASEDIR/${f%/*}"
                        fi
                    done
                done
            done
        fi
    fi
}

# }}}
##############################################################################
# {{{ wfetch

# wfetch <URL> [--uri=<URL-MIRROR>] [--sha256=<SHA256>] [-o <OUTPUT-PATH>] [-q] [--no-buffer]
#
# If -o <OUTPUT-PATH> option is unspecified, the result will be written to ./$(basename <URL>)
#
# If <OUTPUT-PATH> is -, then the result will be written to stdout.
#
# If <OUTPUT-PATH> is . .. or ends with slash(/), then it will be treated as a directory, otherwise, it will be treated as a filepath.
#
# If <OUTPUT-PATH> is treated as a directory, then it will be expanded to <OUTPUT-PATH>/$(basename <URL>)
#
# influential environment variable:
# NDKPKG_URL_TRANSFORM
wfetch() {
    unset FETCH_UTS
    unset FETCH_SHA

    unset FETCH_URL
    unset FETCH_URI

    unset FETCH_PATH

    unset FETCH_OUTPUT_DIR
    unset FETCH_OUTPUT_FILEPATH
    unset FETCH_OUTPUT_FILENAME

    unset FETCH_BUFFER_FILEPATH

    unset FETCH_SHA256_EXPECTED

    unset FETCH_SILENT

    unset NOT_BUFFER

    [ -z "$1" ] && abort 1 "wfetch <URL> [OPTION]... , <URL> must be non-empty."

    if [ -z "$NDKPKG_URL_TRANSFORM" ] ; then
        FETCH_URL="$1"
    else
        FETCH_URL="$("$NDKPKG_URL_TRANSFORM" "$1")" || return 1
    fi

    shift

    while [ -n "$1" ]
    do
        case $1 in
            --uri=*)
                FETCH_URI="${1#*=}"
                ;;
            --sha256=*)
                FETCH_SHA256_EXPECTED="${1#*=}"
                ;;
            -o) shift
                if [ -z "$1" ] ; then
                    abort 1 "wfetch <URL> -o <PATH> , <PATH> must be non-empty."
                else
                    FETCH_PATH="$1"
                fi
                ;;
            -q)
                FETCH_SILENT=1
                ;;
            --no-buffer)
                NOT_BUFFER=1
                ;;
            *)  abort 1 "wfetch <URL> [--uri=<URL-MIRROR>] [--sha256=<SHA256>] [-o <PATH>] [-q] , unrecognized option: $1"
        esac
        shift
    done

    case $FETCH_PATH in
        -)
            FETCH_BUFFER_FILEPATH='-'
            ;;
        .|'')
            FETCH_OUTPUT_DIR='.'
            FETCH_OUTPUT_FILEPATH="$FETCH_OUTPUT_DIR/${FETCH_URL##*/}"
            ;;
        ..)
            FETCH_OUTPUT_DIR='..'
            FETCH_OUTPUT_FILEPATH="$FETCH_OUTPUT_DIR/${FETCH_URL##*/}"
            ;;
        */)
            FETCH_OUTPUT_DIR="${FETCH_PATH%/}"
            FETCH_OUTPUT_FILEPATH="$FETCH_OUTPUT_DIR/${FETCH_URL##*/}"
            ;;
        *)
            FETCH_OUTPUT_DIR="$(dirname "$FETCH_PATH")"
            FETCH_OUTPUT_FILEPATH="$FETCH_PATH"
    esac

    if [ -n "$FETCH_OUTPUT_FILEPATH" ] ; then
        if [ -f "$FETCH_OUTPUT_FILEPATH" ] ; then
            if [ -n "$FETCH_SHA256_EXPECTED" ] ; then
                if [ "$(sha256sum "$FETCH_OUTPUT_FILEPATH" | cut -d ' ' -f1)" = "$FETCH_SHA256_EXPECTED" ] ; then
                    success "$FETCH_OUTPUT_FILEPATH already have been fetched."
                    return 0
                fi
            fi
        fi

        if [ "$NOT_BUFFER" = 1 ] ; then
            FETCH_BUFFER_FILEPATH="$FETCH_OUTPUT_FILEPATH"
        else
            FETCH_UTS="$(date +%s)"

            FETCH_SHA="$(printf '%s\n' "$FETCH_URL:$$:$FETCH_UTS" | sha256sum | cut -d ' ' -f1)"

            FETCH_BUFFER_FILEPATH="$FETCH_OUTPUT_DIR/$FETCH_SHA.tmp"
        fi
    fi

    for FETCH_TOOL in curl wget http aria2c axel
    do
        if command -v "$FETCH_TOOL" > /dev/null ; then
            break
        else
            unset FETCH_TOOL
        fi
    done

    if [ -z "$FETCH_TOOL" ] ; then
        abort 1 "none of curl wget http aria2c axel command was found, please install one of them then try again."
    fi

    if [                -n "$FETCH_OUTPUT_DIR" ] ; then
        if [ !          -d "$FETCH_OUTPUT_DIR" ] ; then
            run install -d "$FETCH_OUTPUT_DIR" || return 1
        fi
    fi

    case $FETCH_TOOL in
        curl)
            FETCH_ARGS='--fail --retry 20 --retry-delay 30 --location'

            if [ "$FETCH_SILENT" = 1 ] ; then
                FETCH_ARGS="$FETCH_ARGS --no-progress-meter"
            fi

            if [ -n "$NDKPKG_DNS_SERVERS" ] ; then
                FETCH_ARGS="$FETCH_ARGS --dns-servers $NDKPKG_DNS_SERVERS"
            fi

            if [ -n "$SSL_CERT_FILE" ] ; then
                FETCH_ARGS="$FETCH_ARGS --cacert $SSL_CERT_FILE"
            fi

            FETCH_ARGS="$FETCH_ARGS -o '$FETCH_BUFFER_FILEPATH'"
            ;;
        wget)
            FETCH_ARGS="--timeout=60 -O '$FETCH_BUFFER_FILEPATH'"
            ;;
        http)
            FETCH_ARGS="--timeout=60 -o '$FETCH_BUFFER_FILEPATH'"
            ;;
        aria2c)
            FETCH_ARGS="-d '$FETCH_OUTPUT_DIR' -o '$FETCH_OUTPUT_FILENAME'"
            ;;
        axel)
            FETCH_ARGS="-o '$FETCH_BUFFER_FILEPATH'"
            ;;
        *)  abort 1 "wfetch() unimplementation: $FETCH_TOOL"
            ;;
    esac

    for i in 1 2 3 4
    do
        case $i in
            1)  URL="$FETCH_URL"
                ;;
            2)  if [ -z "$FETCH_URI" ] ; then
                    if [ -z "$PACKAGE_NAME" ] ; then
                        continue
                    fi

                    URI="${FETCH_URL%%'?'*}"
                    URL="https://distfiles.macports.org/${PACKAGE_NAME%@*}/${URI##*/}"
                else
                    if [ -n "$NDKPKG_URL_TRANSFORM" ] ; then
                        URL="$("$NDKPKG_URL_TRANSFORM" "$FETCH_URI")" || return 1
                    else
                        URL="$FETCH_URI"
                    fi
                fi
                ;;
            3)  case $FETCH_URL in
                    https://ftp.gnu.org/gnu/*)
                        URL="$(printf '%s\n' "$FETCH_URL" | sed 's|ftp\.gnu\.org|mirrors.kernel.org|')"
                        ;;
                    *)  continue
                esac
                ;;
            4)  URI="${FETCH_URL%%'?'*}"
                URL="https://fossies.org/linux/misc/${URI##*/}"
                ;;
        esac

        run "$FETCH_TOOL $FETCH_ARGS '$URL'" && break
    done

    [ $? -eq 0 ] || return 1

    if [ -n "$FETCH_OUTPUT_FILEPATH" ] ; then
        if [ -n "$FETCH_SHA256_EXPECTED" ] ; then
            FETCH_SHA256_ACTUAL="$(sha256sum "$FETCH_BUFFER_FILEPATH" | cut -d ' ' -f1)"

            if [ "$FETCH_SHA256_ACTUAL" != "$FETCH_SHA256_EXPECTED" ] ; then
                abort 1 "sha256sum mismatch.\n    expect : $FETCH_SHA256_EXPECTED\n    actual : $FETCH_SHA256_ACTUAL\n"
            fi
        fi

        if [ "$NOT_BUFFER" != 1 ] ; then
            run mv "$FETCH_BUFFER_FILEPATH" "$FETCH_OUTPUT_FILEPATH"
        fi
    fi
}

# }}}
##############################################################################
# {{{ version

# check if match the condition
#
# condition:
# eq  equal
# ne  not equal
# gt  greater than
# lt  less than
# ge  greater than or equal
# le  less than or equal
#
# examples:
# version_match 1.15.3 eq 1.16.0
# version_match 1.15.3 lt 1.16.0
# version_match 1.15.3 gt 1.16.0
# version_match 1.15.3 le 1.16.0
# version_match 1.15.3 ge 1.16.0
version_match() {
    case $2 in
        eq)  [ "$1"  = "$3" ] ;;
        ne)  [ "$1" != "$3" ] ;;
        le)
            if [ "$1" = "$3" ] ; then
                return 0
            fi
            [ "$1" = "$(printf '%s\n' "$1" "$3" | sort -V | head -n 1)" ]
            ;;
        ge)
            if [ "$1" = "$3" ] ; then
                return 0
            fi
            [ "$1" = "$(printf '%s\n' "$1" "$3" | sort -V | tail -n 1)" ]
            ;;
        lt)
            if [ "$1" = "$3" ] ; then
                return 1
            fi
            [ "$1" = "$(printf '%s\n' "$1" "$3" | sort -V | head -n 1)" ]
            ;;
        gt)
            if [ "$1" = "$3" ] ; then
                return 1
            fi
            [ "$1" = "$(printf '%s\n' "$1" "$3" | sort -V | tail -n 1)" ]
            ;;
        *)  abort 1 "version_compare: $2: not supported operator."
    esac
}

# }}}
##############################################################################
# {{{ __load_formula_repository_config

# __load_formula_repository_config <REPO-NAME> [REPO-PATH]
  __load_formula_repository_config() {
    FORMULA_REPO_NAME="$1"
    FORMULA_REPO_PATH="$NDKPKG_HOME/repos.d/$1"
    FORMULA_REPO_CONFIG_FILEPATH="$FORMULA_REPO_PATH/.ndk-pkg-formula-repo.yml"

    [ -d "$FORMULA_REPO_PATH" ] || abort 1 "formula repository '$1' does not exist."
    [ -f "$FORMULA_REPO_CONFIG_FILEPATH" ] || abort 1 "formula repository '$1' is broken."

    FORMULA_REPO_URL=
    FORMULA_REPO_BRANCH=
    FORMULA_REPO_PINNED=
    FORMULA_REPO_ENABLED=
    FORMULA_REPO_TIMESTAMP_CREATED=
    FORMULA_REPO_TIMESTAMP_UPDATED=

    FORMULA_REPO_URL="$(yq .url "$FORMULA_REPO_CONFIG_FILEPATH")"

    [ "$FORMULA_REPO_URL" = null ] && abort 1 "formula repository '$1' is broken."

    FORMULA_REPO_BRANCH="$(yq .branch "$FORMULA_REPO_CONFIG_FILEPATH")"

    [ "$FORMULA_REPO_BRANCH" = null ] && abort 1 "formula repository '$1' is broken."

    FORMULA_REPO_PINNED="$(yq .pinned "$FORMULA_REPO_CONFIG_FILEPATH")"

    case $FORMULA_REPO_PINNED in
        0|1) ;;
        *)   abort 1 "formula repository '$1' is broken."
    esac

    FORMULA_REPO_ENABLED="$(yq .enabled "$FORMULA_REPO_CONFIG_FILEPATH")"

    case $FORMULA_REPO_ENABLED in
        0|1) ;;
        *)   abort 1 "formula repository '$1' is broken."
    esac

    FORMULA_REPO_TIMESTAMP_CREATED="$(yq .created "$FORMULA_REPO_CONFIG_FILEPATH")"

    [ "${#FORMULA_REPO_TIMESTAMP_CREATED}" -eq 10 ] || abort 1 "formula repository '$1' is broken."

    FORMULA_REPO_TIMESTAMP_UPDATED="$(yq .updated "$FORMULA_REPO_CONFIG_FILEPATH")"

    if [ "$FORMULA_REPO_TIMESTAMP_UPDATED" = null ] ; then
           FORMULA_REPO_TIMESTAMP_UPDATED=
    else
        [ "${#FORMULA_REPO_TIMESTAMP_UPDATED}" -eq 10 ] || abort 1 "formula repository '$1' is broken."
    fi
}

# }}}
##############################################################################
# {{{ ndk-pkg formula-repo-add

# __create_a_formula_repository <REPO-NAME> <REPO-URL> [--branch=VALUE --pin/--unpin --enable/--disable --sync]
  __create_a_formula_repository() {
    [ -z "$1" ] && abort 1 "please specify a repository name."
    [ -z "$2" ] && abort 1 "please specify a repository url."

    FORMULA_REPO_NAME="$1"
    FORMULA_REPO_URL="$2"

    shift 2

    FORMULA_REPO_BRANCH=
    FORMULA_REPO_PINNED=
    FORMULA_REPO_ENABLED=
    FORMULA_REPO_SYNC=

    while [ -n "$1" ]
    do
        case $1 in
            --branch=*)
                FORMULA_REPO_BRANCH="${1#*=}"
                ;;
            --pin)
                FORMULA_REPO_PINNED=1
                ;;
            --unpin)
                FORMULA_REPO_PINNED=0
                ;;
            --enable)
                FORMULA_REPO_ENABLED=1
                ;;
            --disable)
                FORMULA_REPO_ENABLED=0
                ;;
            --sync)
                FORMULA_REPO_SYNC=1
                ;;
            *)  abort 1 "unrecognized argument: $1"
        esac
        shift
    done

    FORMULA_REPO_BRANCH="${FORMULA_REPO_BRANCH:-master}"
    FORMULA_REPO_PINNED="${FORMULA_REPO_PINNED:-0}"
    FORMULA_REPO_ENABLED="${FORMULA_REPO_ENABLED:-1}"

    FORMULA_REPO_PATH="$NDKPKG_HOME/repos.d/$FORMULA_REPO_NAME"

    if [ -d "$FORMULA_REPO_PATH" ] ; then
        abort 1 "formula repository '$FORMULA_REPO_NAME' already exists."
    fi

    printf '%b\n' "${COLOR_PURPLE}==> ndk-pkg formula repository${COLOR_OFF} ${COLOR_GREEN}$FORMULA_REPO_NAME${COLOR_OFF} ${COLOR_PURPLE} is being added${COLOR_OFF}"

    SESSION_DIR="$NDKPKG_HOME/run/$$/$FORMULA_REPO_NAME"

    run rm -rf     "$SESSION_DIR"
    run install -d "$SESSION_DIR"
    run cd         "$SESSION_DIR"

    if [ "$FORMULA_REPO_SYNC" = 1 ] ; then
        if [ -z "$NDKPKG_URL_TRANSFORM" ] ; then
            GIT_FETCH_URL="$FORMULA_REPO_URL"
        else
            GIT_FETCH_URL="$("$NDKPKG_URL_TRANSFORM" "$FORMULA_REPO_URL")"
        fi

        run git -c init.defaultBranch=master init
        run git remote add origin "$GIT_FETCH_URL"
        run git -c protocol.version=2 fetch --progress origin "+refs/heads/$FORMULA_REPO_BRANCH:refs/remotes/origin/$FORMULA_REPO_BRANCH"
        run git checkout --progress --force -B "$FORMULA_REPO_BRANCH" "refs/remotes/origin/$FORMULA_REPO_BRANCH"
    else
        run git -c init.defaultBranch=master init
        run git remote add origin "$FORMULA_REPO_URL"
    fi

    cat > .ndk-pkg-formula-repo.yml <<EOF
url: $FORMULA_REPO_URL
branch: $FORMULA_REPO_BRANCH
pinned: $FORMULA_REPO_PINNED
enabled: $FORMULA_REPO_ENABLED
created: $TIMESTAMP_UNIX
EOF

    run install -d        "$NDKPKG_FORMULA_REPO_ROOT"
    run mv "$SESSION_DIR" "$NDKPKG_FORMULA_REPO_ROOT/"
}

# }}}
##############################################################################
# {{{ ndk-pkg formula-repo-del

# __delete_a_formula_repository <REPO-NAME>
  __delete_a_formula_repository() {
    [ -z "$1" ] && abort 1 "please specify a repository name."

    [ "$1" = 'official-core' ] && abort 1 "formula repository 'official-core' is not allowed to delete."

    if [ -d    "$NDKPKG_HOME/repos.d/$1" ] ; then
        rm -rf "$NDKPKG_HOME/repos.d/$1"
    else
        abort 1 "formula repository '$1' does not exist."
    fi
}

# }}}
##############################################################################
# {{{ ndk-pkg formula-repo-sync

# __sync_the_given_formula_repository <REPO-NAME>
  __sync_the_given_formula_repository() {
    [ -z "$1" ] && abort 1 "please specify a repository name."

    __load_formula_repository_config "$1"

    [ "$FORMULA_REPO_PINNED" = 1 ] && abort 1 "'formula repository '$FORMULA_REPO_NAME' is pinned."

    if [ -z "$NDKPKG_URL_TRANSFORM" ] ; then
        GIT_FETCH_URL="$FORMULA_REPO_URL"
    else
        GIT_FETCH_URL="$("$NDKPKG_URL_TRANSFORM" "$FORMULA_REPO_URL")"
    fi

    printf '%b\n' "${COLOR_PURPLE}==> ndk-pkg formula repository${COLOR_OFF} ${COLOR_GREEN}$FORMULA_REPO_NAME${COLOR_OFF} ${COLOR_PURPLE}is being updated${COLOR_OFF}"

    run cd "$FORMULA_REPO_PATH"
    run git remote set-url origin "$GIT_FETCH_URL"
    run git -c protocol.version=2 fetch --progress origin "+refs/heads/$FORMULA_REPO_BRANCH:refs/remotes/origin/$FORMULA_REPO_BRANCH"
    run git checkout --progress --force -B "$FORMULA_REPO_BRANCH" "refs/remotes/origin/$FORMULA_REPO_BRANCH"

    cat > .ndk-pkg-formula-repo.yml <<EOF
url: $FORMULA_REPO_URL
branch: $FORMULA_REPO_BRANCH
pinned: $FORMULA_REPO_PINNED
enabled: $FORMULA_REPO_ENABLED
created: $FORMULA_REPO_TIMESTAMP_CREATED
updated: $TIMESTAMP_UNIX
EOF
}

# }}}
##############################################################################
# {{{ ndk-pkg formula-repo-conf

# __conf_the_given_formula_repository <REPO-NAME> [--url=VALUE --branch=VALUE --pin/--unpin --enable/--disable]
  __conf_the_given_formula_repository() {
    [ -z "$1" ] && abort 1 "please specify a repository name."
    [ -z "$2" ] && abort 1 "at least one option should be given. supported options are: --url=VALUE --branch=VALUE --pin/--unpin --enable/--disable"

    __load_formula_repository_config "$1"

    shift

    while [ -n "$1" ]
    do
        case $1 in
            --url=*)
                FORMULA_REPO_URL="${1#*=}"

                if [ -z "$FORMULA_REPO_URL" ] ; then
                    abort 1 "--url=<VALUE> , <VALUE> should be non-empty."
                else
                    FORMULA_REPO_URL="$FORMULA_REPO_URL"
                fi
                ;;
            --branch=*)
                FORMULA_REPO_BRANCH="${1#*=}"

                if [ -z "$FORMULA_REPO_BRANCH" ] ; then
                    abort 1 "--branch=<VALUE> , <VALUE> should be non-empty."
                else
                    FORMULA_REPO_BRANCH="$FORMULA_REPO_BRANCH"
                fi
                ;;
            --pin)
                FORMULA_REPO_PINNED=1
                ;;
            --unpin)
                FORMULA_REPO_PINNED=0
                ;;
            --enable)
                FORMULA_REPO_ENABLED=1
                ;;
            --disable)
                FORMULA_REPO_ENABLED=0
                ;;
            *)  abort 1 "unrecognized argument: $1"
        esac
        shift
    done

    if [ -z "$FORMULA_REPO_TIMESTAMP_UPDATED" ] ; then
        cat > "$FORMULA_REPO_PATH/.ndk-pkg-formula-repo.yml" <<EOF
url:  $FORMULA_REPO_URL
branch: $FORMULA_REPO_BRANCH
pinned:  $FORMULA_REPO_PINNED
enabled: $FORMULA_REPO_ENABLED
created: $FORMULA_REPO_TIMESTAMP_CREATED
EOF
    else
        cat > "$FORMULA_REPO_PATH/.ndk-pkg-formula-repo.yml" <<EOF
url:  $FORMULA_REPO_URL
branch: $FORMULA_REPO_BRANCH
pinned:  $FORMULA_REPO_PINNED
enabled: $FORMULA_REPO_ENABLED
created: $FORMULA_REPO_TIMESTAMP_CREATED
updated: $FORMULA_REPO_TIMESTAMP_UPDATED
EOF
fi
}

# }}}
##############################################################################
# {{{ ndk-pkg formula-repo-info

# __info_the_given_formula_repository <REPO-NAME>
  __info_the_given_formula_repository() {
    [ -z "$1" ] && abort 1 "please specify a repository name."

    __load_formula_repository_config "$1"

    case $FORMULA_REPO_PINNED in
        0)  FORMULA_REPO_PINNED=no ;;
        1)  FORMULA_REPO_PINNED=yes ;;
    esac

    case $FORMULA_REPO_ENABLED in
        0)  FORMULA_REPO_ENABLED=no ;;
        1)  FORMULA_REPO_ENABLED=yes ;;
    esac

    cat <<EOF
name: $FORMULA_REPO_NAME
path: $FORMULA_REPO_PATH
url:  $FORMULA_REPO_URL
branch: $FORMULA_REPO_BRANCH
pinned: $FORMULA_REPO_PINNED
enabled: $FORMULA_REPO_ENABLED
created: $(date -d "@$FORMULA_REPO_TIMESTAMP_CREATED" '+%Y-%m-%d %H:%M:%S%:z')
EOF

    if [ -n "$FORMULA_REPO_TIMESTAMP_UPDATED" ] ; then
        printf 'updated: %s\n' "$(date -d "@$FORMULA_REPO_TIMESTAMP_UPDATED" '+%Y-%m-%d %H:%M:%S%:z')"
    fi
}

# }}}
##############################################################################
# {{{ ndk-pkg update

__sync_available_formula_repositories() {
    [ -d "$NDKPKG_FORMULA_REPO_ROOT" ] && {
        for item in $(cd "$NDKPKG_FORMULA_REPO_ROOT" && ls)
        do
            if [ -f "$NDKPKG_FORMULA_REPO_ROOT/$item/.ndk-pkg-formula-repo.yml" ] ; then
                __sync_the_given_formula_repository "$item"
            fi
        done
    }

    [ -d "$NDKPKG_FORMULA_REPO_ROOT/official-core" ] || {
        __create_a_formula_repository official-core "$NDKPKG_OFFICIAL_FORMULA_REPO_URL" --sync
    }
}

# }}}
##############################################################################
# {{{ ndk-pkg formula-repo-list

__list_available_formula_repositories() {
    [ -d "$NDKPKG_FORMULA_REPO_ROOT" ] || return 0

    I=0

    for item in $(cd "$NDKPKG_FORMULA_REPO_ROOT" && ls)
    do
        if [ -f "$NDKPKG_FORMULA_REPO_ROOT/$item/.ndk-pkg-formula-repo.yml" ] ; then
            I="$(expr "$I" + 1)"

            [ "$I" -gt 1 ] && printf '\n'

            __info_the_given_formula_repository "$item"
        fi
    done
}

# __path_of_formula_of_the_given_package <PACKAGE-NAME>
  __path_of_formula_of_the_given_package() {
    [ -z "$1" ] && abort 1 "__path_of_formula_of_the_given_package <PACKAGE-NAME>, <PACKAGE-NAME> is unspecified."

    if [ -n "$NDKPKG_FORMULA_SEARCH_DIRS" ] ; then
        export IFS=':'

        for FORMULA_SEARCH_DIR in $NDKPKG_FORMULA_SEARCH_DIRS
        do
            FORMULA_FILEPATH="$FORMULA_SEARCH_DIR/$1.yml"

            if [ -f           "$FORMULA_FILEPATH" ] ; then
                printf '%s\n' "$FORMULA_FILEPATH"
                unset IFS
                return 0
            fi
        done

        unset IFS
    fi

    [ -d "$NDKPKG_FORMULA_REPO_ROOT" ] || return 0

    FORMULA_REPOSITORY_NAMES=

    for item in $(cd "$NDKPKG_FORMULA_REPO_ROOT" && ls)
    do
        if [ -f "$NDKPKG_FORMULA_REPO_ROOT/$item/.ndk-pkg-formula-repo.yml" ] ; then
            FORMULA_REPOSITORY_NAMES="$FORMULA_REPOSITORY_NAMES $item"
        fi
    done

    for FORMULA_REPOSITORY_NAME in $FORMULA_REPOSITORY_NAMES
    do
        FORMULA_FILEPATH="$NDKPKG_FORMULA_REPO_ROOT/$FORMULA_REPOSITORY_NAME/formula/$1.yml"

        if [ -f           "$FORMULA_FILEPATH" ] ; then
            printf '%s\n' "$FORMULA_FILEPATH"
            return 0
        fi
    done
}

# }}}
##############################################################################
# {{{ formula

filetype_from_url() {
    # remove query params
    URL="${1%%'?'*}"

    FNAME="${URL##*/}"

    case $FNAME in
        *.tar.gz|*.tgz)
            printf '%s\n' '.tgz'
            ;;
        *.tar.lz|*.tlz)
            printf '%s\n' '.tlz'
            ;;
        *.tar.xz|*.txz)
            printf '%s\n' '.txz'
            ;;
        *.tar.bz2|*.tbz2)
            printf '%s\n' '.tbz2'
            ;;
        *.*)printf '%s\n' ".${FNAME##*.}"
    esac
}

# __load_formula_of_the_given_package <PACKAGE-NAME> [FORMULA-FILEPATH]
  __load_formula_of_the_given_package() {
    if [ -z "$1" ] ; then
        abort 1 "__load_formula_of_the_given_package <PACKAGE-NAME> [FORMULA-FILEPATH], <PACKAGE-NAME> is unspecified."
    else
        PACKAGE_NAME="$1"
        PACKAGE_NAME_UPPERCASE_UNDERSCORE=$(printf '%s\n' "$PACKAGE_NAME" | tr a-z A-Z | tr '@+-.' '_')
    fi

    #########################################################################################

    if [ -z "$2" ] ; then
        PACKAGE_FORMULA_FILEPATH="$(__path_of_formula_of_the_given_package "$1")"

        if [ -z "$PACKAGE_FORMULA_FILEPATH" ] ; then
            abort 1 "package '$1' is not available."
        fi
    else
        PACKAGE_FORMULA_FILEPATH="$2"
    fi

    #########################################################################################

    unset PACKAGE_PKGTYPE

    unset PACKAGE_SUMMARY

    unset PACKAGE_LICENSE

    unset PACKAGE_VERSION
    unset PACKAGE_VERSION_MAJOR
    unset PACKAGE_VERSION_MINOR
    unset PACKAGE_VERSION_PATCH
    unset PACKAGE_VERSION_TWEAK

    unset PACKAGE_WEB_URL

    unset PACKAGE_GIT_URL
    unset PACKAGE_GIT_SHA
    unset PACKAGE_GIT_REF
    unset PACKAGE_GIT_NTH

    unset PACKAGE_SRC_URL
    unset PACKAGE_SRC_URI
    unset PACKAGE_SRC_SHA
    unset PACKAGE_SRC_FILENAME
    unset PACKAGE_SRC_FILETYPE
    unset PACKAGE_SRC_FILEPATH

    unset PACKAGE_FIX_URL
    unset PACKAGE_FIX_URI
    unset PACKAGE_FIX_SHA
    unset PACKAGE_FIX_OPT
    unset PACKAGE_FIX_FILENAME
    unset PACKAGE_FIX_FILETYPE
    unset PACKAGE_FIX_FILEPATH

    unset PACKAGE_RES_URL
    unset PACKAGE_RES_URI
    unset PACKAGE_RES_SHA
    unset PACKAGE_RES_FILENAME
    unset PACKAGE_RES_FILETYPE
    unset PACKAGE_RES_FILEPATH

    # space-separated    perl modules that are depended by this package when installing, which will be installed via cpan
    unset PACKAGE_DEP_PLM

    # space-separated python packages that are depended by this package when installing, which will be installed via pip
    unset PACKAGE_DEP_PIP

    # space-separated   ruby packages that are depended by this package when installing, which will be installed via gem
    unset PACKAGE_DEP_GEM

    # space-separated nodejs packages that are depended by this package when installing, which will be installed via npm
    unset PACKAGE_DEP_NPM

    # space-separated   uppm packages that are depended by this package when installing, which will be installed via uppm
    unset PACKAGE_DEP_UPP

    # space-separated ndk-pkg packages that are depended by this package when installing and/or runtime, which will be installed via ndk-pkg
    unset PACKAGE_DEP_PKG

    unset PACKAGE_DEP_LIB

    unset PACKAGE_PPFLAGS
    unset PACKAGE_CCFLAGS
    unset PACKAGE_XXFLAGS
    unset PACKAGE_LDFLAGS

    unset PACKAGE_DOFETCH
    unset PACKAGE_DO12345
    unset PACKAGE_DOPATCH
    unset PACKAGE_PREPARE
    unset PACKAGE_DOBUILD
    unset PACKAGE_DOTWEAK

    unset PACKAGE_PATCHES
    unset PACKAGE_RESLIST

    unset PACKAGE_CAVEATS

    unset PACKAGE_LINKAGE

    unset PACKAGE_LTOABLE

    # whether the installed files can be moved/copied to other locations
    unset PACKAGE_MOVABLE

    unset PACKAGE_SUPPORT_BUILD_ON_MACOS
    unset PACKAGE_SUPPORT_BUILD_IN_PARALLEL

    unset PACKAGE_SUPPORT_CREATE_FULLY_STATICALLY_LINKED_EXECUTABLE
    unset PACKAGE_SUPPORT_CREATE_MOSTLY_STATICALLY_LINKED_EXECUTABLE

    unset PACKAGE_BSYSTEM
    unset PACKAGE_BSYSTEM_MASTER

    unset PACKAGE_USE_WAF
    unset PACKAGE_USE_GO
    unset PACKAGE_USE_GN
    unset PACKAGE_USE_RAKE
    unset PACKAGE_USE_NINJA
    unset PACKAGE_USE_GMAKE
    unset PACKAGE_USE_CMAKE
    unset PACKAGE_USE_XMAKE
    unset PACKAGE_USE_MESON
    unset PACKAGE_USE_CARGO
    unset PACKAGE_USE_AUTOGENSH
    unset PACKAGE_USE_AUTOTOOLS
    unset PACKAGE_USE_CONFIGURE
    unset PACKAGE_USE_NDK_BUILD

    # directory relative to $PACKAGE_WORKING_DIR/src, which contains build script such as autogen.sh, configure, Makefile, CMakeLists.txt, meson.build, Cargo.toml, xmake.lua, etc.
    unset PACKAGE_BSCRIPT

    # whether to build in build script directory, otherwise build in build dir
    unset PACKAGE_BINBSTD

    unset PACKAGE_DEVELOPER

    # package support min sdk api level
    unset PACKAGE_API_MIN

    #########################################################################################

    PACKAGE_API_MIN="$(yq '.api-min | select(. != null)' "$PACKAGE_FORMULA_FILEPATH")"

    PACKAGE_PKGTYPE="$(yq '.pkgtype | select(. != null)' "$PACKAGE_FORMULA_FILEPATH")"
    PACKAGE_LINKAGE="$(yq '.linkage | select(. != null)' "$PACKAGE_FORMULA_FILEPATH")"
    PACKAGE_SUMMARY="$(yq '.summary | select(. != null)' "$PACKAGE_FORMULA_FILEPATH")"
    PACKAGE_LICENSE="$(yq '.license | select(. != null)' "$PACKAGE_FORMULA_FILEPATH")"
    PACKAGE_VERSION="$(yq '.version | select(. != null)' "$PACKAGE_FORMULA_FILEPATH")"

    PACKAGE_WEB_URL="$(yq '.web-url | select(. != null)' "$PACKAGE_FORMULA_FILEPATH")"

    PACKAGE_GIT_URL="$(yq '.git-url | select(. != null)' "$PACKAGE_FORMULA_FILEPATH")"
    PACKAGE_GIT_SHA="$(yq '.git-sha | select(. != null)' "$PACKAGE_FORMULA_FILEPATH")"
    PACKAGE_GIT_REF="$(yq '.git-ref | select(. != null)' "$PACKAGE_FORMULA_FILEPATH")"
    PACKAGE_GIT_NTH="$(yq '.git-nth | select(. != null)' "$PACKAGE_FORMULA_FILEPATH")"

    PACKAGE_SRC_URL="$(yq '.src-url | select(. != null)' "$PACKAGE_FORMULA_FILEPATH")"
    PACKAGE_SRC_URI="$(yq '.src-uri | select(. != null)' "$PACKAGE_FORMULA_FILEPATH")"
    PACKAGE_SRC_SHA="$(yq '.src-sha | select(. != null)' "$PACKAGE_FORMULA_FILEPATH")"

    PACKAGE_FIX_URL="$(yq '.fix-url | select(. != null)' "$PACKAGE_FORMULA_FILEPATH")"
    PACKAGE_FIX_URI="$(yq '.fix-uri | select(. != null)' "$PACKAGE_FORMULA_FILEPATH")"
    PACKAGE_FIX_SHA="$(yq '.fix-sha | select(. != null)' "$PACKAGE_FORMULA_FILEPATH")"
    PACKAGE_FIX_OPT="$(yq '.fix-opt | select(. != null)' "$PACKAGE_FORMULA_FILEPATH")"

    PACKAGE_RES_URL="$(yq '.res-url | select(. != null)' "$PACKAGE_FORMULA_FILEPATH")"
    PACKAGE_RES_URI="$(yq '.res-uri | select(. != null)' "$PACKAGE_FORMULA_FILEPATH")"
    PACKAGE_RES_SHA="$(yq '.res-sha | select(. != null)' "$PACKAGE_FORMULA_FILEPATH")"

    PACKAGE_DEP_PKG="$(yq '.dep-pkg | select(. != null)' "$PACKAGE_FORMULA_FILEPATH")"
    PACKAGE_DEP_LIB="$(yq '.dep-lib | select(. != null)' "$PACKAGE_FORMULA_FILEPATH")"
    PACKAGE_DEP_UPP="$(yq '.dep-upp | select(. != null)' "$PACKAGE_FORMULA_FILEPATH")"
    PACKAGE_DEP_PLM="$(yq '.dep-plm | select(. != null)' "$PACKAGE_FORMULA_FILEPATH")"
    PACKAGE_DEP_PIP="$(yq '.dep-pip | select(. != null)' "$PACKAGE_FORMULA_FILEPATH")"
    PACKAGE_DEP_GEM="$(yq '.dep-gem | select(. != null)' "$PACKAGE_FORMULA_FILEPATH")"
    PACKAGE_DEP_NPM="$(yq '.dep-npm | select(. != null)' "$PACKAGE_FORMULA_FILEPATH")"

    PACKAGE_BSYSTEM="$(yq '.bsystem | select(. != null)' "$PACKAGE_FORMULA_FILEPATH")"
    PACKAGE_BSCRIPT="$(yq '.bscript | select(. != null)' "$PACKAGE_FORMULA_FILEPATH")"
    PACKAGE_BINBSTD="$(yq '.binbstd | select(. != null)' "$PACKAGE_FORMULA_FILEPATH")"
    PACKAGE_LTOABLE="$(yq '.ltoable | select(. != null)' "$PACKAGE_FORMULA_FILEPATH")"
    PACKAGE_MOVABLE="$(yq '.movable | select(. != null)' "$PACKAGE_FORMULA_FILEPATH")"

    PACKAGE_CCFLAGS="$(yq '.ccflags | select(. != null)' "$PACKAGE_FORMULA_FILEPATH")"
    PACKAGE_XXFLAGS="$(yq '.xxflags | select(. != null)' "$PACKAGE_FORMULA_FILEPATH")"
    PACKAGE_PPFLAGS="$(yq '.ppflags | select(. != null)' "$PACKAGE_FORMULA_FILEPATH")"
    PACKAGE_LDFLAGS="$(yq '.ldflags | select(. != null)' "$PACKAGE_FORMULA_FILEPATH")"

    PACKAGE_DOFETCH="$(yq '.dofetch | select(. != null)' "$PACKAGE_FORMULA_FILEPATH")"
    PACKAGE_DO12345="$(yq '.do12345 | select(. != null)' "$PACKAGE_FORMULA_FILEPATH")"
    PACKAGE_DOPATCH="$(yq '.dopatch | select(. != null)' "$PACKAGE_FORMULA_FILEPATH")"
    PACKAGE_PREPARE="$(yq '.prepare | select(. != null)' "$PACKAGE_FORMULA_FILEPATH")"
    PACKAGE_DOBUILD="$(yq '.install | select(. != null)' "$PACKAGE_FORMULA_FILEPATH")"
    PACKAGE_DOTWEAK="$(yq '.dotweak | select(. != null)' "$PACKAGE_FORMULA_FILEPATH")"

    PACKAGE_PATCHES="$(yq '.patches | select(. != null)' "$PACKAGE_FORMULA_FILEPATH")"
    PACKAGE_RESLIST="$(yq '.reslist | select(. != null)' "$PACKAGE_FORMULA_FILEPATH")"

    PACKAGE_BINDENV="$(yq '.bindenv | select(. != null)' "$PACKAGE_FORMULA_FILEPATH")"
    PACKAGE_WRAPPER="$(yq '.wrapper | select(. != null)' "$PACKAGE_FORMULA_FILEPATH")"
    PACKAGE_CAVEATS="$(yq '.caveats | select(. != null)' "$PACKAGE_FORMULA_FILEPATH")"

    PACKAGE_SUPPORT_BUILD_IN_PARALLEL="$(yq '.parallel | select(. != null)' "$PACKAGE_FORMULA_FILEPATH")"

    PACKAGE_DEVELOPER="$(yq '.developer | select(. != null)' "$PACKAGE_FORMULA_FILEPATH")"

    #########################################################################################

    PACKAGE_DISABLE="$(yq '.disable | select(. != null)' "$PACKAGE_FORMULA_FILEPATH")"

    for item in $PACKAGE_DISABLE
    do
        case $item in
            macos) PACKAGE_SUPPORT_BUILD_ON_MACOS=0 ;;
            *)  abort 1 "unrecognized disable item '$item' in $PACKAGE_FORMULA_FILEPATH"
        esac
    done

    #########################################################################################

    if [ -z "$PACKAGE_SRC_URL" ] && [ -n "$PACKAGE_SRC_URI" ] ; then
        PACKAGE_SRC_URL="$PACKAGE_SRC_URI"
        PACKAGE_SRC_URI=
    fi

    if [ -z "$PACKAGE_FIX_URL" ] && [ -n "$PACKAGE_FIX_URI" ] ; then
        PACKAGE_FIX_URL="$PACKAGE_FIX_URI"
        PACKAGE_FIX_URI=
    fi

    if [ -z "$PACKAGE_RES_URL" ] && [ -n "$PACKAGE_RES_URI" ] ; then
        PACKAGE_RES_URL="$PACKAGE_RES_URI"
        PACKAGE_RES_URI=
    fi

    #########################################################################################

    if [ -z "$PACKAGE_SUMMARY" ] ; then
        abort 1 "summary mapping not found in $PACKAGE_FORMULA_FILEPATH"
    fi

    if [ -n "$PACKAGE_FIX_URL" ] && [ -n "$PACKAGE_PATCHES" ] ; then
        abort 1 "fix-url and patches mapping shouldn't be used together in $PACKAGE_FORMULA_FILEPATH"
    fi

    if [ -n "$PACKAGE_RES_URL" ] && [ -n "$PACKAGE_RESLIST" ] ; then
        abort 1 "res-url and reslist mapping shouldn't be used together in $PACKAGE_FORMULA_FILEPATH"
    fi

    if [ -n "$PACKAGE_GIT_NTH" ] ; then
        isInteger "$PACKAGE_GIT_NTH" || abort "the value of git-nth mapping should be an integer."
    fi

    if [ -n "$PACKAGE_API_MIN" ] ; then
        isInteger "$PACKAGE_API_MIN" || abort "the value of api-min mapping should be an integer."
    fi

    #########################################################################################

    unset PACKAGE_NEED_CURL
    unset PACKAGE_NEED_BTAR

    #########################################################################################

    if [ -n "$PACKAGE_SRC_URL" ] ; then
        case $PACKAGE_SRC_URL in
            dir://*)
                PACKAGE_SRC_FILETYPE=.dir
                PACKAGE_SRC_FILEPATH=$(printf '%s\n' "$PACKAGE_SRC_URL" | cut -c7-)

                if [ -z "$PACKAGE_VERSION" ] ; then
                    PACKAGE_VERSION="$(date -u -d "@$TIMESTAMP_UNIX" '+%Y.%m.%d')"
                fi
                ;;
            file://*)
                PACKAGE_SRC_FILEPATH=$(printf '%s\n' "$PACKAGE_SRC_URL" | cut -c8-)
                PACKAGE_SRC_FILENAME="$(basename "$PACKAGE_SRC_FILEPATH")"
                PACKAGE_SRC_FILETYPE="$(filetype_from_url "$PACKAGE_SRC_FILENAME")"

                if [ -z "$PACKAGE_VERSION" ] ; then
                    PACKAGE_VERSION="$(date -u -d "@$TIMESTAMP_UNIX" '+%Y.%m.%d')"
                fi
                ;;
            *)  PACKAGE_SRC_FILETYPE="$(filetype_from_url "$PACKAGE_SRC_URL")"
                PACKAGE_SRC_FILENAME="$PACKAGE_SRC_SHA$PACKAGE_SRC_FILETYPE"
                PACKAGE_SRC_FILEPATH="$NDKPKG_DOWNLOADS_DIR/$PACKAGE_SRC_FILENAME"

                if [ -z "$PACKAGE_SRC_SHA" ] ; then
                    abort 1 "src-sha mapping not found in $PACKAGE_FORMULA_FILEPATH"
                fi

                if [ -z "$PACKAGE_GIT_URL" ] ; then
                    case $PACKAGE_SRC_URL in
                        https://github.com/*/*/releases/*)
                            PACKAGE_GIT_URL="${PACKAGE_SRC_URL%%/releases/*}"
                            ;;
                        https://github.com/*/*/archive/*)
                            PACKAGE_GIT_URL="${PACKAGE_SRC_URL%%/archive/*}"
                            ;;
                        https://gitlab.com/*/*/-/archive/*)
                            PACKAGE_GIT_URL="${PACKAGE_SRC_URL%%/-/archive/*}"
                            ;;
                    esac
                fi

                if [ -z "$PACKAGE_VERSION" ] ; then
                    PACKAGE_VERSION="$(basename "$PACKAGE_SRC_URL" | tr '_@' - | sed -e 's|\.tar\.[glx]z$||' -e 's|\.tar\.bz2$||' -e 's|\.t[glx]z$||' -e 's|\.zip$||' -e 's|-stable||' -e 's|-source||' -e 's|[-.]src$||' -e 's|\.orig||' -e 's|\.orig||' | awk -F- '{print $NF}')"
                    case $PACKAGE_VERSION in
                        '') abort 1 "version mapping not found in $PACKAGE_FORMULA_FILEPATH" ;;
                        v*) PACKAGE_VERSION=$(printf '%s\n' "$PACKAGE_VERSION" | cut -c2-)
                    esac
                fi

                PACKAGE_NEED_CURL=1

                case $PACKAGE_SRC_FILETYPE in
                    .zip|.txz|.tgz|.tlz|.tbz2|.crate)
                        PACKAGE_NEED_BTAR=1
                esac
        esac
    else
        if [ -n "$PACKAGE_GIT_URL" ] ; then
            PACKAGE_SRC_FILETYPE=.git

            if [ -z "$PACKAGE_VERSION" ] ; then
                PACKAGE_VERSION="$(date -u -d "@$TIMESTAMP_UNIX" '+%Y.%m.%d')"
            fi

            PACKAGE_DEP_UPP="$PACKAGE_DEP_UPP git"
        fi
    fi

    #########################################################################################

    if [ -z "$PACKAGE_WEB_URL" ] ; then
        if [ -z "$PACKAGE_GIT_URL" ] ; then
            if [ -z "$PACKAGE_SRC_URL" ] ; then
                abort 1 "none of web-url, git-url, src-url mapping was found in $PACKAGE_FORMULA_FILEPATH"
            else
                PACKAGE_WEB_URL="${PACKAGE_SRC_URL%/*}"
            fi
        else
            PACKAGE_WEB_URL="$PACKAGE_GIT_URL"
        fi
    fi

    #########################################################################################

    [ -n "$PACKAGE_FIX_URL" ] && {
        [ -z "$PACKAGE_FIX_SHA" ] && abort 1 "fix-sha mapping not found in $PACKAGE_FORMULA_FILEPATH"

        PACKAGE_FIX_FILETYPE="$(filetype_from_url "$PACKAGE_FIX_URL")"
        PACKAGE_FIX_FILENAME="$PACKAGE_FIX_SHA$PACKAGE_FIX_FILETYPE"
        PACKAGE_FIX_FILEPATH="$NDKPKG_DOWNLOADS_DIR/$PACKAGE_FIX_FILENAME"

        PACKAGE_NEED_CURL=1

        case $PACKAGE_SRC_FILETYPE in
            .zip|.txz|.tgz|.tlz|.tbz2|.crate)
                PACKAGE_NEED_BTAR=1
        esac
    }

    #########################################################################################

    [ -n "$PACKAGE_RES_URL" ] && {
        [ -z "$PACKAGE_RES_SHA" ] && abort 1 "res-sha mapping not found in $PACKAGE_FORMULA_FILEPATH"

        PACKAGE_RES_FILETYPE="$(filetype_from_url "$PACKAGE_RES_URL")"
        PACKAGE_RES_FILENAME="$PACKAGE_RES_SHA$PACKAGE_RES_FILETYPE"
        PACKAGE_RES_FILEPATH="$NDKPKG_DOWNLOADS_DIR/$PACKAGE_RES_FILENAME"

        PACKAGE_NEED_CURL=1

        case $PACKAGE_SRC_FILETYPE in
            .zip|.txz|.tgz|.tlz|.tbz2|.crate)
                PACKAGE_NEED_BTAR=1
        esac
    }

    #########################################################################################

    export IFS='
'

    for LINE in $PACKAGE_PATCHES $PACKAGE_RESLIST
    do
        SHA="$(printf '%s\n' "$LINE" | cut -d '|' -f1)"
        URL="$(printf '%s\n' "$LINE" | cut -d '|' -f2)"

        FILETYPE="$(filetype_from_url "$URL")"

        if [ "${#SHA}" -ne 64 ] ; then
            abort 1 "not a sha256sum in line: $LINE in file: $PACKAGE_FORMULA_FILEPATH"
        fi

        PACKAGE_NEED_CURL=1

        case $FILETYPE in
            .zip|.txz|.tgz|.tlz|.tbz2|.crate)
                PACKAGE_NEED_BTAR=1
        esac
    done

    unset IFS

    #########################################################################################

    [ "$PACKAGE_NEED_CURL" = 1 ] && PACKAGE_DEP_UPP="$PACKAGE_DEP_UPP curl"
    [ "$PACKAGE_NEED_BTAR" = 1 ] && PACKAGE_DEP_UPP="$PACKAGE_DEP_UPP bsdtar"

    #########################################################################################

    [ -n "$PACKAGE_VERSION" ] && {
        PACKAGE_VERSION_MAJOR="$(printf '%s\n' "$PACKAGE_VERSION" | cut -d. -f1)"
        PACKAGE_VERSION_MINOR="$(printf '%s\n' "$PACKAGE_VERSION" | cut -d. -f2)"
        PACKAGE_VERSION_PATCH="$(printf '%s\n' "$PACKAGE_VERSION" | cut -d. -f3)"
        PACKAGE_VERSION_TWEAK="$(printf '%s\n' "$PACKAGE_VERSION" | cut -d. -f4)"
    }

    #########################################################################################

    if [     -z "$PACKAGE_BSYSTEM" ] ; then
        if [ -z "$PACKAGE_DOBUILD" ] ; then
            abort 1 "neither bsystem nor install mapping was found in $PACKAGE_FORMULA_FILEPATH"
        else
            for FirstWordOfLineInInstallActions in $(printf '%s\n' "$PACKAGE_DOBUILD" | sed 's|^[[:space:]]*||' | cut -d ' ' -f1)
            do
                case "$FirstWordOfLineInInstallActions" in
                    configure)    PACKAGE_BSYSTEM=configure ; break ;;
                    cmakew)       PACKAGE_BSYSTEM=cmake ; break ;;
                    xmakew)       PACKAGE_BSYSTEM=xmake ; break ;;
                    mesonw)       PACKAGE_BSYSTEM=meson ; break ;;
                    gmakew)       PACKAGE_BSYSTEM=gmake ; break ;;
                    cargow)       PACKAGE_BSYSTEM=cargo ; break ;;
                    go|gow)       PACKAGE_BSYSTEM=go    ; break ;;
                    gn|gnw)       PACKAGE_BSYSTEM=gn    ; break ;;
                    waf)          PACKAGE_BSYSTEM=waf   ; break ;;
                esac
            done
        fi
    fi

    PACKAGE_BSYSTEM_MASTER="${PACKAGE_BSYSTEM%%' '*}"

    #########################################################################################

    for BSTSTEM in $PACKAGE_BSYSTEM
    do
        case $BSTSTEM in
            ndk-build)   PACKAGE_USE_NDK_BUILD=1 ; PACKAGE_USE_GMAKE=1 ;;
            autogen)     PACKAGE_USE_AUTOGENSH=1 ; PACKAGE_USE_GMAKE=1 ;;
            autotools)   PACKAGE_USE_AUTOTOOLS=1 ; PACKAGE_USE_GMAKE=1 ;;
            configure)   PACKAGE_USE_CONFIGURE=1 ; PACKAGE_USE_GMAKE=1 ;;
            cmake+gmake) PACKAGE_USE_CMAKE=1     ; PACKAGE_USE_GMAKE=1 ;;
            cmake+ninja) PACKAGE_USE_CMAKE=1     ; PACKAGE_USE_NINJA=1 ;;
            cmake)       PACKAGE_USE_CMAKE=1     ; PACKAGE_USE_NINJA=1 ;;
            xmake)       PACKAGE_USE_XMAKE=1     ;;
            meson)       PACKAGE_USE_MESON=1     ; PACKAGE_USE_NINJA=1 ;;
            ninja)       PACKAGE_USE_NINJA=1     ;;
            gmake)       PACKAGE_USE_GMAKE=1     ;;
            rake)        PACKAGE_USE_RAKE=1      ;;
            cargo)       PACKAGE_USE_CARGO=1     ;;
            go)          PACKAGE_USE_GO=1        ;;
            gn)          PACKAGE_USE_GN=1        ;;
            waf)         PACKAGE_USE_WAF=1       ;;
        esac
    done

    #########################################################################################

    [ -z "$PACKAGE_DOBUILD" ] && {
        case $PACKAGE_BSYSTEM_MASTER in
            autogen)   PACKAGE_DOBUILD='configure' ;;
            autotools) PACKAGE_DOBUILD='configure' ;;
            configure) PACKAGE_DOBUILD='configure' ;;
            cmake*)    PACKAGE_DOBUILD='cmakew' ;;
            xmake)     PACKAGE_DOBUILD='xmakew' ;;
            meson)     PACKAGE_DOBUILD='mesonw' ;;
            ninja)     PACKAGE_DOBUILD='ninjaw clean && ninjaw && ninjaw install' ;;
            gmake)     PACKAGE_DOBUILD='gmakew clean && gmakew && gmakew install' ;;
            cargo)     PACKAGE_DOBUILD='cargow install' ;;
            go)        PACKAGE_DOBUILD='gow' ;;
            gn)        PACKAGE_DOBUILD='gnw' ;;
            waf)       PACKAGE_DOBUILD='waf' ;;
        esac
    }

    #########################################################################################

    if [ -n "$PACKAGE_FIX_URL" ] || [ -n "$PACKAGE_PATCHES" ] ; then
        PACKAGE_DEP_UPP="$PACKAGE_DEP_UPP patch"
    fi

    [ -n "$PACKAGE_DEP_PIP" ]        && PACKAGE_DEP_UPP="$PACKAGE_DEP_UPP python3"
    [ -n "$PACKAGE_DEP_PLM" ]        && PACKAGE_DEP_UPP="$PACKAGE_DEP_UPP perl gmake"

    [ "$PACKAGE_USE_NDK_BUILD" = 1 ] && PACKAGE_DEP_PIP="$PACKAGE_DEP_PIP gmake"
    [ "$PACKAGE_USE_AUTOGENSH" = 1 ] && PACKAGE_DEP_UPP="$PACKAGE_DEP_UPP automake"
    [ "$PACKAGE_USE_AUTOTOOLS" = 1 ] && PACKAGE_DEP_UPP="$PACKAGE_DEP_UPP automake"
    [ "$PACKAGE_USE_CONFIGURE" = 1 ] && PACKAGE_DEP_UPP="$PACKAGE_DEP_UPP gmake"
    [ "$PACKAGE_USE_MESON"     = 1 ] && PACKAGE_DEP_UPP="$PACKAGE_DEP_UPP python3"
    [ "$PACKAGE_USE_MESON"     = 1 ] && PACKAGE_DEP_PIP="$PACKAGE_DEP_PIP meson"
    [ "$PACKAGE_USE_CMAKE"     = 1 ] && PACKAGE_DEP_UPP="$PACKAGE_DEP_UPP cmake"
    [ "$PACKAGE_USE_GMAKE"     = 1 ] && PACKAGE_DEP_UPP="$PACKAGE_DEP_UPP gmake"
    [ "$PACKAGE_USE_XMAKE"     = 1 ] && PACKAGE_DEP_UPP="$PACKAGE_DEP_UPP xmake"
    [ "$PACKAGE_USE_NINJA"     = 1 ] && PACKAGE_DEP_UPP="$PACKAGE_DEP_UPP ninja"
    [ "$PACKAGE_USE_RAKE"      = 1 ] && PACKAGE_DEP_UPP="$PACKAGE_DEP_UPP ruby"
    [ "$PACKAGE_USE_GO"        = 1 ] && PACKAGE_DEP_UPP="$PACKAGE_DEP_UPP golang"
    [ "$PACKAGE_USE_GN"        = 1 ] && PACKAGE_DEP_UPP="$PACKAGE_DEP_UPP gn ninja"
    [ "$PACKAGE_USE_WAF"       = 1 ] && PACKAGE_DEP_UPP="$PACKAGE_DEP_UPP python3"

    PACKAGE_DEP_UPP="${PACKAGE_DEP_UPP#' '}"

    #########################################################################################

    [ "$PACKAGE_USE_WAF"   = 1 ] && PACKAGE_BINBSTD=1
    [ "$PACKAGE_USE_GO"    = 1 ] && PACKAGE_BINBSTD=1
    [ "$PACKAGE_USE_CARGO" = 1 ] && PACKAGE_BINBSTD=1
    [ "$PACKAGE_USE_XMAKE" = 1 ] && PACKAGE_BINBSTD=1

    if [ -z  "$PACKAGE_BINBSTD" ] ; then
        if [ "$PACKAGE_BSYSTEM_MASTER" = gmake ] ; then
            PACKAGE_BINBSTD=1
        else
            PACKAGE_BINBSTD=0
        fi
    fi

    #########################################################################################

    [ -z "$PACKAGE_LTOABLE" ] && PACKAGE_LTOABLE=1
    [ -z "$PACKAGE_MOVABLE" ] && PACKAGE_MOVABLE=1

    [ -z "$PACKAGE_SUPPORT_BUILD_ON_MACOS"    ] && PACKAGE_SUPPORT_BUILD_ON_MACOS=1
    [ -z "$PACKAGE_SUPPORT_BUILD_IN_PARALLEL" ] && PACKAGE_SUPPORT_BUILD_IN_PARALLEL=1

    #########################################################################################

    if [ -z "$PACKAGE_PKGTYPE" ] ; then
        case $PACKAGE_NAME in
            lib*)   PACKAGE_PKGTYPE=lib ;;
            *lib)   PACKAGE_PKGTYPE=lib ;;
            *-dev)  PACKAGE_PKGTYPE=lib ;;
               *)   PACKAGE_PKGTYPE=exe ;;
        esac
    fi

    #########################################################################################

    if [ "$PACKAGE_PKGTYPE" = exe ] ; then
        case $PACKAGE_LINKAGE in
            '')
                PACKAGE_SUPPORT_CREATE_FULLY_STATICALLY_LINKED_EXECUTABLE=1
                PACKAGE_SUPPORT_CREATE_MOSTLY_STATICALLY_LINKED_EXECUTABLE=1
                ;;
            static)
                PACKAGE_SUPPORT_CREATE_FULLY_STATICALLY_LINKED_EXECUTABLE=1
                PACKAGE_SUPPORT_CREATE_MOSTLY_STATICALLY_LINKED_EXECUTABLE=0
                ;;
            static/pie)
                PACKAGE_SUPPORT_CREATE_FULLY_STATICALLY_LINKED_EXECUTABLE=1
                PACKAGE_SUPPORT_CREATE_MOSTLY_STATICALLY_LINKED_EXECUTABLE=0
                ;;
            shared)
                PACKAGE_SUPPORT_CREATE_FULLY_STATICALLY_LINKED_EXECUTABLE=0
                PACKAGE_SUPPORT_CREATE_MOSTLY_STATICALLY_LINKED_EXECUTABLE=1
                ;;
            shared/most)
                PACKAGE_SUPPORT_CREATE_FULLY_STATICALLY_LINKED_EXECUTABLE=0
                PACKAGE_SUPPORT_CREATE_MOSTLY_STATICALLY_LINKED_EXECUTABLE=0
                ;;
            *)  abort 1 "unsupported linkage: $PACKAGE_LINKAGE"
        esac
    fi

    #########################################################################################

    # https://github.com/golang/go/issues/59942
    if [ "$PACKAGE_USE_GO" = 1 ] ; then
        PACKAGE_SUPPORT_CREATE_FULLY_STATICALLY_LINKED_EXECUTABLE=0
    fi
}

# }}}
##############################################################################
# {{{ receipt

# __load_receipt_of_the_given_package <PACKAGE-NAME|PACKAGE-SPEC>
  __load_receipt_of_the_given_package() {
    PACKAGE_SPEC=
    PACKAGE_SPEC="$(inspect_package_spec "$1")"

    is_package_installed "$PACKAGE_SPEC" || return $?

    PACKAGE_INSTALLED_DIR="$(readlink -f "$NDKPKG_PACKAGE_INSTALLED_ROOT/$PACKAGE_SPEC")"

    PACKAGE_RECEIPT_FILEPATH="$PACKAGE_INSTALLED_DIR/.ndk-pkg/RECEIPT.yml"

    unset RECEIPT_PACKAGE_PKGNAME
    unset RECEIPT_PACKAGE_PKGTYPE

    unset RECEIPT_PACKAGE_PROFILE

    unset RECEIPT_PACKAGE_SUMMARY
    unset RECEIPT_PACKAGE_VERSION
    unset RECEIPT_PACKAGE_LICENSE

    unset RECEIPT_PACKAGE_WEB_URL

    unset RECEIPT_PACKAGE_GIT_URL
    unset RECEIPT_PACKAGE_GIT_SHA
    unset RECEIPT_PACKAGE_GIT_REF
    unset RECEIPT_PACKAGE_GIT_NTH

    unset RECEIPT_PACKAGE_SRC_URL
    unset RECEIPT_PACKAGE_SRC_URI
    unset RECEIPT_PACKAGE_SRC_SHA

    unset RECEIPT_PACKAGE_FIX_URL
    unset RECEIPT_PACKAGE_FIX_URI
    unset RECEIPT_PACKAGE_FIX_SHA
    unset RECEIPT_PACKAGE_FIX_OPT

    unset RECEIPT_PACKAGE_RES_URL
    unset RECEIPT_PACKAGE_RES_URI
    unset RECEIPT_PACKAGE_RES_SHA

    unset RECEIPT_PACKAGE_PATCHES
    unset RECEIPT_PACKAGE_RESLIST

    unset RECEIPT_PACKAGE_DEP_PKG
    unset RECEIPT_PACKAGE_DEP_LIB
    unset RECEIPT_PACKAGE_DEP_UPP
    unset RECEIPT_PACKAGE_DEP_PIP
    unset RECEIPT_PACKAGE_DEP_PLM

    unset RECEIPT_PACKAGE_BSYSTEM
    unset RECEIPT_PACKAGE_BSCRIPT

    unset RECEIPT_PACKAGE_DOFETCH
    unset RECEIPT_PACKAGE_DO12345
    unset RECEIPT_PACKAGE_DOPATCH
    unset RECEIPT_PACKAGE_PREPARE
    unset RECEIPT_PACKAGE_DOBUILD
    unset RECEIPT_PACKAGE_DOTWEAK

    unset RECEIPT_PACKAGE_BINDENV
    unset RECEIPT_PACKAGE_CAVEATS

    unset RECEIPT_PACKAGE_MOVABLE
    unset RECEIPT_PACKAGE_LTOABLE

    unset RECEIPT_PACKAGE_BUILTBY
    unset RECEIPT_PACKAGE_BUILTAT

    unset RECEIPT_PACKAGE_BUILTFOR
    unset RECEIPT_PACKAGE_BUILTFOR_PLATFORM
    unset RECEIPT_PACKAGE_BUILTFOR_PLATFORM_NAME
    unset RECEIPT_PACKAGE_BUILTFOR_PLATFORM_VERS
    unset RECEIPT_PACKAGE_BUILTFOR_PLATFORM_ARCH

    unset RECEIPT_PACKAGE_DEVELOPER

    unset RECEIPT_PACKAGE_API_MIN
    unset RECEIPT_PACKAGE_NDKVERS

    #########################################################################################

    RECEIPT_PACKAGE_PKGNAME="$(yq '.pkgname | select(. != null)' "$PACKAGE_RECEIPT_FILEPATH")"
    RECEIPT_PACKAGE_PKGTYPE="$(yq '.pkgtype | select(. != null)' "$PACKAGE_RECEIPT_FILEPATH")"

    RECEIPT_PACKAGE_PROFILE="$(yq '.profile | select(. != null)' "$PACKAGE_RECEIPT_FILEPATH")"

    RECEIPT_PACKAGE_SUMMARY="$(yq '.summary | select(. != null)' "$PACKAGE_RECEIPT_FILEPATH")"
    RECEIPT_PACKAGE_LICENSE="$(yq '.license | select(. != null)' "$PACKAGE_RECEIPT_FILEPATH")"
    RECEIPT_PACKAGE_VERSION="$(yq '.version | select(. != null)' "$PACKAGE_RECEIPT_FILEPATH")"

    RECEIPT_PACKAGE_WEB_URL="$(yq '.web-url | select(. != null)' "$PACKAGE_RECEIPT_FILEPATH")"

    RECEIPT_PACKAGE_GIT_URL="$(yq '.git-url | select(. != null)' "$PACKAGE_RECEIPT_FILEPATH")"
    RECEIPT_PACKAGE_GIT_SHA="$(yq '.git-sha | select(. != null)' "$PACKAGE_RECEIPT_FILEPATH")"
    RECEIPT_PACKAGE_GIT_REF="$(yq '.git-ref | select(. != null)' "$PACKAGE_RECEIPT_FILEPATH")"
    RECEIPT_PACKAGE_GIT_NTH="$(yq '.git-nth | select(. != null)' "$PACKAGE_RECEIPT_FILEPATH")"

    RECEIPT_PACKAGE_SRC_URL="$(yq '.src-url | select(. != null)' "$PACKAGE_RECEIPT_FILEPATH")"
    RECEIPT_PACKAGE_SRC_URI="$(yq '.src-uri | select(. != null)' "$PACKAGE_RECEIPT_FILEPATH")"
    RECEIPT_PACKAGE_SRC_SHA="$(yq '.src-sha | select(. != null)' "$PACKAGE_RECEIPT_FILEPATH")"

    RECEIPT_PACKAGE_FIX_URL="$(yq '.fix-url | select(. != null)' "$PACKAGE_RECEIPT_FILEPATH")"
    RECEIPT_PACKAGE_FIX_URI="$(yq '.fix-uri | select(. != null)' "$PACKAGE_RECEIPT_FILEPATH")"
    RECEIPT_PACKAGE_FIX_SHA="$(yq '.fix-sha | select(. != null)' "$PACKAGE_RECEIPT_FILEPATH")"
    RECEIPT_PACKAGE_FIX_OPT="$(yq '.fix-opt | select(. != null)' "$PACKAGE_RECEIPT_FILEPATH")"

    RECEIPT_PACKAGE_RES_URL="$(yq '.res-url | select(. != null)' "$PACKAGE_RECEIPT_FILEPATH")"
    RECEIPT_PACKAGE_RES_URI="$(yq '.res-uri | select(. != null)' "$PACKAGE_RECEIPT_FILEPATH")"
    RECEIPT_PACKAGE_RES_SHA="$(yq '.res-sha | select(. != null)' "$PACKAGE_RECEIPT_FILEPATH")"
    RECEIPT_PACKAGE_RESLIST="$(yq '.reslist | select(. != null)' "$PACKAGE_RECEIPT_FILEPATH")"
    RECEIPT_PACKAGE_PATCHES="$(yq '.patches | select(. != null)' "$PACKAGE_RECEIPT_FILEPATH")"

    RECEIPT_PACKAGE_DEP_PKG="$(yq '.dep-pkg | select(. != null)' "$PACKAGE_RECEIPT_FILEPATH")"
    RECEIPT_PACKAGE_DEP_LIB="$(yq '.dep-lib | select(. != null)' "$PACKAGE_RECEIPT_FILEPATH")"
    RECEIPT_PACKAGE_DEP_UPP="$(yq '.dep-upp | select(. != null)' "$PACKAGE_RECEIPT_FILEPATH")"
    RECEIPT_PACKAGE_DEP_PIP="$(yq '.dep-pip | select(. != null)' "$PACKAGE_RECEIPT_FILEPATH")"
    RECEIPT_PACKAGE_DEP_PLM="$(yq '.dep-plm | select(. != null)' "$PACKAGE_RECEIPT_FILEPATH")"

    RECEIPT_PACKAGE_BSYSTEM="$(yq '.bsystem | select(. != null)' "$PACKAGE_RECEIPT_FILEPATH")"
    RECEIPT_PACKAGE_BSCRIPT="$(yq '.bscript | select(. != null)' "$PACKAGE_RECEIPT_FILEPATH")"
    RECEIPT_PACKAGE_BINBSTD="$(yq '.binbstd | select(. != null)' "$PACKAGE_RECEIPT_FILEPATH")"

    RECEIPT_PACKAGE_CCFLAGS="$(yq '.ccflags | select(. != null)' "$PACKAGE_RECEIPT_FILEPATH")"
    RECEIPT_PACKAGE_XXFLAGS="$(yq '.xxflags | select(. != null)' "$PACKAGE_RECEIPT_FILEPATH")"
    RECEIPT_PACKAGE_PPFLAGS="$(yq '.ppflags | select(. != null)' "$PACKAGE_RECEIPT_FILEPATH")"
    RECEIPT_PACKAGE_LDFLAGS="$(yq '.ldflags | select(. != null)' "$PACKAGE_RECEIPT_FILEPATH")"

    RECEIPT_PACKAGE_DOFETCH="$(yq '.dofetch | select(. != null)' "$PACKAGE_RECEIPT_FILEPATH")"
    RECEIPT_PACKAGE_DO12345="$(yq '.do12345 | select(. != null)' "$PACKAGE_RECEIPT_FILEPATH")"
    RECEIPT_PACKAGE_DOPATCH="$(yq '.dopatch | select(. != null)' "$PACKAGE_RECEIPT_FILEPATH")"
    RECEIPT_PACKAGE_PREPARE="$(yq '.prepare | select(. != null)' "$PACKAGE_RECEIPT_FILEPATH")"
    RECEIPT_PACKAGE_DOBUILD="$(yq '.install | select(. != null)' "$PACKAGE_RECEIPT_FILEPATH")"
    RECEIPT_PACKAGE_DOTWEAK="$(yq '.dotweak | select(. != null)' "$PACKAGE_RECEIPT_FILEPATH")"

    RECEIPT_PACKAGE_BINDENV="$(yq '.bindenv | select(. != null)' "$PACKAGE_RECEIPT_FILEPATH")"
    RECEIPT_PACKAGE_CAVEATS="$(yq '.caveats | select(. != null)' "$PACKAGE_RECEIPT_FILEPATH")"

    RECEIPT_PACKAGE_MOVABLE="$(yq '.movable | select(. != null)' "$PACKAGE_RECEIPT_FILEPATH")"
    RECEIPT_PACKAGE_LTOABLE="$(yq '.ltoable | select(. != null)' "$PACKAGE_RECEIPT_FILEPATH")"

    RECEIPT_PACKAGE_API_MIN="$(yq '.api-min | select(. != null)' "$PACKAGE_RECEIPT_FILEPATH")"
    RECEIPT_PACKAGE_NDKVERS="$(yq '.ndkvers | select(. != null)' "$PACKAGE_RECEIPT_FILEPATH")"

    RECEIPT_PACKAGE_BUILTBY="$(yq '.builtby | select(. != null)' "$PACKAGE_RECEIPT_FILEPATH")"
    RECEIPT_PACKAGE_BUILTAT="$(yq '.builtat | select(. != null)' "$PACKAGE_RECEIPT_FILEPATH")"

    RECEIPT_PACKAGE_BUILTFOR="$(yq '.builtfor | select(. != null)' "$PACKAGE_RECEIPT_FILEPATH")"

    RECEIPT_PACKAGE_DEVELOPER="$(yq '.developer | select(. != null)' "$PACKAGE_RECEIPT_FILEPATH")"

    #########################################################################################

    [ -z "$RECEIPT_PACKAGE_PKGNAME" ] && abort 1 "receipt scheme error. pkgname mapping was not found in $PACKAGE_RECEIPT_FILEPATH."
    [ -z "$RECEIPT_PACKAGE_PKGTYPE" ] && abort 1 "receipt scheme error. pkgtype mapping was not found in $PACKAGE_RECEIPT_FILEPATH."
    [ -z "$RECEIPT_PACKAGE_VERSION" ] && abort 1 "receipt scheme error. version mapping was not found in $PACKAGE_RECEIPT_FILEPATH."
    [ -z "$RECEIPT_PACKAGE_SUMMARY" ] && abort 1 "receipt scheme error. summary mapping was not found in $PACKAGE_RECEIPT_FILEPATH."
    [ -z "$RECEIPT_PACKAGE_WEB_URL" ] && abort 1 "receipt scheme error. web-url mapping was not found in $PACKAGE_RECEIPT_FILEPATH."
    [ -z "$RECEIPT_PACKAGE_BUILTBY" ] && abort 1 "receipt scheme error. builtby mapping was not found in $PACKAGE_RECEIPT_FILEPATH."
    [ -z "$RECEIPT_PACKAGE_BUILTAT" ] && abort 1 "receipt scheme error. builtat mapping was not found in $PACKAGE_RECEIPT_FILEPATH."

    [ "${#RECEIPT_PACKAGE_BUILTAT}" -eq 10 ] || abort 1 "receipt scheme error. builtat mapping's value length must be 10."

    if [ "${PACKAGE_SPEC#*/}" != "$RECEIPT_PACKAGE_PKGNAME" ] ; then
        error "$PACKAGE_RECEIPT_FILEPATH is broken. value of RECEIPT_PACKAGE_PKGNAME does not identical with your request: ${PACKAGE_SPEC#*/}"
        return 1
    fi

    if [ "${PACKAGE_SPEC%/*}" != "$RECEIPT_PACKAGE_BUILTFOR" ] ; then
        error "$PACKAGE_RECEIPT_FILEPATH is broken. value of RECEIPT_PACKAGE_BUILTFOR does not identical with your request: ${PACKAGE_SPEC%/*}"
        return 1
    fi

    #########################################################################################

    RECEIPT_PACKAGE_BUILTFOR_PLATFORM="$RECEIPT_PACKAGE_BUILTFOR"

    case $RECEIPT_PACKAGE_BUILTFOR in
        android-[1-9][0-9]-armeabi-v7a)
            RECEIPT_PACKAGE_BUILTFOR_PLATFORM_ARCH='armv7a'
            ;;
        android-[1-9][0-9]-arm64-v8a)
            RECEIPT_PACKAGE_BUILTFOR_PLATFORM_ARCH='aarch64'
            ;;
        android-[1-9][0-9]-x86)
            RECEIPT_PACKAGE_BUILTFOR_PLATFORM_ARCH='i686'
            ;;
        android-[1-9][0-9]-x86_64)
            RECEIPT_PACKAGE_BUILTFOR_PLATFORM_ARCH='x86_64'
            ;;
        *)  abort 1 "$PACKAGE_RECEIPT_FILEPATH is broken. value of RECEIPT_PACKAGE_BUILTFOR is invalid: $RECEIPT_PACKAGE_BUILTFOR"
    esac

    RECEIPT_PACKAGE_BUILTFOR_PLATFORM_VERS="$(printf '%s\n' "$RECEIPT_PACKAGE_BUILTFOR" | cut -d- -f2)"

    RECEIPT_PACKAGE_BUILTFOR_PLATFORM_NAME=android
}

# }}}
##############################################################################
# {{{ ndk-pkg is-available

# check if the given package is available
# if the version condition is given, check if the condition is matched
#
# condition operator:
# eq  equal
# ne  not equal
# gt  greater than
# lt  less than
# ge  greater than or equal
# le  less than or equal
#
# examples:
# is_package_available automake eq 1.16.0
# is_package_available automake lt 1.16.0
# is_package_available automake gt 1.16.0
# is_package_available automake le 1.16.0
# is_package_available automake ge 1.16.0
# is_package_available automake
is_package_available() {
    case $# in
        0)  abort 1 "package name is unspecified." ;;
        1)  [ -n "$(__path_of_formula_of_the_given_package "$1")" ] ;;
        3)  __load_formula_of_the_given_package "$1"
            shift
            version_match "$PACKAGE_VERSION" "$@"
            ;;
        *)  abort 1 "is available command only accept 1 or 3 argument."
    esac
}

# }}}
##############################################################################
# {{{ ndk-pkg is-installed

# is_package_installed <PACKAGE-SPEC>
  is_package_installed() {
    (
        PACKAGE_INSTALL_DIR="$NDKPKG_PACKAGE_INSTALLED_ROOT/$1"

        [ -L "$PACKAGE_INSTALL_DIR" ] || exit 11
        [ -d "$PACKAGE_INSTALL_DIR" ] || exit 12
        [ -f "$PACKAGE_INSTALL_DIR/.ndk-pkg/MANIFEST.txt" ] || exit 14
        [ -f "$PACKAGE_INSTALL_DIR/.ndk-pkg/RECEIPT.yml" ] || exit 15
    )
}

# }}}
##############################################################################
# {{{ ndk-pkg is-outdated

# is_package__outdated <PACKAGE-SPEC>
  is_package__outdated() {
    __load_receipt_of_the_given_package "$1"
    __load_formula_of_the_given_package "${1#*/}"
    version_match "$PACKAGE_VERSION" gt "$RECEIPT_PACKAGE_VERSION"
}

# }}}
##############################################################################
# {{{ ndk-pkg ls-available [-v] [--yaml | --json]

__list_available_packages() {
    unset OUTPUT_MODE
    unset OUTPUT_TYPE

    for arg in $@
    do
        case $arg in
            -v)     OUTPUT_MODE=full ;;
            --json) OUTPUT_TYPE=json ;;
            --yaml) OUTPUT_TYPE=yaml ;;
            *) abort 1 "unrecognized argument: $arg"
        esac
    done

    if [ -z "$OUTPUT_MODE" ] ; then
        __list_available_package_names
    else
        AVAILABLE_PACKAGE_NAMES="$(__list_available_package_names)"

        [ -z "$AVAILABLE_PACKAGE_NAMES" ] && return 0

        IS_FIRST_ELEMENT=1

        case $OUTPUT_TYPE in
            yaml|'')
                for PKGNAME in $AVAILABLE_PACKAGE_NAMES
                do
                    if [ "$IS_FIRST_ELEMENT" = 1 ] ; then
                        unset IS_FIRST_ELEMENT
                    else
                        printf '%s\n' '---'
                    fi
                    __info_the_given_available_package_as_yaml "$PKGNAME"
                done
                ;;
            json)
                printf '%s\n' '['

                for PKGNAME in $AVAILABLE_PACKAGE_NAMES
                do
                    if [ "$IS_FIRST_ELEMENT" = 1 ] ; then
                        unset IS_FIRST_ELEMENT
                    else
                        printf '%s\n' ','
                    fi
                    __info_the_given_available_package_as_json "$PKGNAME"
                done

                printf '%s\n' ']'
                ;;
        esac
    fi
}

__list_available_package_names() {
    [ -d "$NDKPKG_FORMULA_REPO_ROOT" ] || return 0

    {
        FORMULA_REPOSITORY_NAMES=

        for item in $(cd "$NDKPKG_FORMULA_REPO_ROOT" && ls)
        do
            if [ -f "$NDKPKG_FORMULA_REPO_ROOT/$item/.ndk-pkg-formula-repo.yml" ] ; then
                FORMULA_REPOSITORY_NAMES="$FORMULA_REPOSITORY_NAMES $item"
            fi
        done

        for FORMULA_REPOSITORY_NAME in $FORMULA_REPOSITORY_NAMES
        do
            FORMULA_SEARCH_DIR="$NDKPKG_FORMULA_REPO_ROOT/$FORMULA_REPOSITORY_NAME/formula"

            if [ -d  "$FORMULA_SEARCH_DIR" ] ; then
                find "$FORMULA_SEARCH_DIR" -maxdepth 1 -type f -name '*.yml' -exec basename {} .yml \; || return 1
            fi
        done
    } | sort | uniq
}

# }}}
##############################################################################
# {{{ ndk-pkg ls-installed

__list_installed_packages() {
    if [ -d "$NDKPKG_PACKAGE_INSTALLED_ROOT" ] ; then
         cd "$NDKPKG_PACKAGE_INSTALLED_ROOT" || return 1
        find . -maxdepth 2 -mindepth 2 -type l -regex '\./android-[1-9][0-9]-\(armeabi-v7a\|arm64-v8a\|x86\|x86_64\)/[^/]*' -printf '%P\n'
    else
        return 0
    fi
}

# }}}
##############################################################################
# {{{ ndk-pkg ls-outdated

__list__outdated_packages() {
    for PACKAGE_SPEC in $(__list_installed_packages)
    do
        if is_package__outdated "$PACKAGE_SPEC" ; then
            printf '%s\n' "$PACKAGE_SPEC"
        fi
    done
}

# }}}
##############################################################################
# {{{ ndk-pkg search <REGULAR-EXPRESSION-PATTERN> [-v]

__search_packages() {
    [ -z "$1" ] && abort 1 "please specify a regular express partten."

    AVAILABLE_PACKAGE_NAMES_ALL="$(__list_available_package_names)"

    [ -z "$AVAILABLE_PACKAGE_NAMES_ALL" ] && return 0

    AVAILABLE_PACKAGE_NAMES_FILTERED="$(printf '%s\n' $AVAILABLE_PACKAGE_NAMES_ALL | grep "$1" || true)"

    [ -z "$AVAILABLE_PACKAGE_NAMES_FILTERED" ] && return 0

    case $2 in
        '') printf '%s\n' $AVAILABLE_PACKAGE_NAMES_FILTERED ;;
        -v) IS_FIRST_ELEMENT=1

            for PKGNAME in $AVAILABLE_PACKAGE_NAMES_FILTERED
            do
                if [ "$IS_FIRST_ELEMENT" = 1 ] ; then
                    unset IS_FIRST_ELEMENT
                else
                    printf '%s\n' '---'
                fi

                __info_the_given_available_package_as_yaml "$PKGNAME"
            done
            ;;
        *)  abort 1 "unrecognzied argument: $2"
    esac
}

# }}}
##############################################################################
# {{{ ndk-pkg info

# __info_the_given_available_package_as_json <PACKAGE-NAME>
  __info_the_given_available_package_as_json() {
    __load_formula_of_the_given_package "$1"

    jq  --null-input \
        --arg pkgname "$PACKAGE_NAME" \
        --arg pkgtype "$PACKAGE_PKGTYPE" \
        --arg version "$PACKAGE_VERSION" \
        --arg summary "$PACKAGE_SUMMARY" \
        --arg license "$PACKAGE_LICENSE" \
        --arg web_url "$PACKAGE_WEB_URL" \
        --arg git_url "$PACKAGE_GIT_URL" \
        --arg git_sha "$PACKAGE_GIT_SHA" \
        --arg git_ref "$PACKAGE_GIT_REF" \
        --arg git_nth "$PACKAGE_GIT_NTH" \
        --arg src_url "$PACKAGE_SRC_URL" \
        --arg src_uri "$PACKAGE_SRC_URI" \
        --arg src_sha "$PACKAGE_SRC_SHA" \
        --arg fix_url "$PACKAGE_FIX_URL" \
        --arg fix_uri "$PACKAGE_FIX_URI" \
        --arg fix_sha "$PACKAGE_FIX_SHA" \
        --arg res_url "$PACKAGE_RES_URL" \
        --arg res_uri "$PACKAGE_RES_URI" \
        --arg res_sha "$PACKAGE_RES_SHA" \
        --arg patches "$PACKAGE_PATCHES" \
        --arg reslist "$PACKAGE_RESLIST" \
        --arg dep_pkg "$PACKAGE_DEP_PKG" \
        --arg dep_lib "$PACKAGE_DEP_LIB" \
        --arg dep_upp "$PACKAGE_DEP_UPP" \
        --arg dep_pip "$PACKAGE_DEP_PIP" \
        --arg dep_plm "$PACKAGE_DEP_PLM" \
        --arg dofetch "$PACKAGE_DOFETCH" \
        --arg do12345 "$PACKAGE_DO12345" \
        --arg dopatch "$PACKAGE_DOPATCH" \
        --arg prepare "$PACKAGE_PREPARE" \
        --arg install "$PACKAGE_DOBUILD" \
        --arg dotweak "$PACKAGE_DOTWEAK" \
        --arg movable "$PACKAGE_MOVABLE" \
        --arg ltoable "$PACKAGE_LTOABLE" \
        --arg caveats "$PACKAGE_CAVEATS" \
        --arg bsystem "$PACKAGE_BSYSTEM" \
        --arg binbstd "$PACKAGE_BINBSTD" \
        --arg ccflags "$PACKAGE_CCFLAGS" \
        --arg xxflags "$PACKAGE_XXFLAGS" \
        --arg ppflags "$PACKAGE_PPFLAGS" \
        --arg ldflags "$PACKAGE_LDFLAGS" \
        --arg api_min "$PACKAGE_API_MIN" \
        --arg developer "$PACKAGE_DEVELOPER" \
'{
    "pkgname":$pkgname,
    "pkgtype":$pkgtype,
    "version":$version,
    "license":$license,
    "summary":$summary,
    "web-url":$web_url,
    "git-url":$git_url,
    "git-sha":$git_sha,
    "git-ref":$git_ref,
    "git-nth":$git_nth,
    "src-url":$src_url,
    "src-uri":$src_uri,
    "src-sha":$src_sha,
    "fix-url":$fix_url,
    "fix-uri":$fix_uri,
    "fix-sha":$fix_sha,
    "res-url":$res_url,
    "res-uri":$res_uri,
    "res-sha":$res_sha,
    "patches":$patches,
    "reslist":$reslist,
    "dep-pkg":$dep_pkg,
    "dep-lib":$dep_lib,
    "dep-upp":$dep_upp,
    "dep-pip":$dep_pip,
    "dep-plm":$dep_plm,
    "bsystem":$bsystem,
    "binbstd":$binbstd,
    "ccflags":$ccflags,
    "xxflags":$xxflags,
    "ppflags":$ppflags,
    "ldflags":$ldflags,
    "api-min":$api_min,
    "developer":$developer,
    "dofetch":$dofetch,
    "do12345":$do12345,
    "dopatch":$dopatch,
    "prepare":$prepare,
    "install":$install,
    "dotweak":$dotweak,
    "ltoable":$ltoable,
    "movable":$movable,
    "caveats":$caveats
}' | jq 'with_entries(select(.value != ""))'
}

# __info_the_given_available_package_as_yaml <PACKAGE-NAME>
  __info_the_given_available_package_as_yaml() {
    __load_formula_of_the_given_package "$1"

    if is_package_installed "$1" ; then
        PACKAGE_INSTALLED=yes
    else
        PACKAGE_INSTALLED=no
    fi

    {
    cat <<EOF
pkgname: $PACKAGE_NAME
pkgtype: $PACKAGE_PKGTYPE
version: $PACKAGE_VERSION
license: $PACKAGE_LICENSE
summary: $PACKAGE_SUMMARY
web-url: $PACKAGE_WEB_URL
git-url: $PACKAGE_GIT_URL
git-sha: $PACKAGE_GIT_SHA
git-ref: $PACKAGE_GIT_REF
git-nth: $PACKAGE_GIT_NTH
src-url: $PACKAGE_SRC_URL
src-uri: $PACKAGE_SRC_URI
src-sha: $PACKAGE_SRC_SHA
fix-url: $PACKAGE_FIX_URL
fix-uri: $PACKAGE_FIX_URI
fix-sha: $PACKAGE_FIX_SHA
res-url: $PACKAGE_RES_URL
res-uri: $PACKAGE_RES_URI
res-sha: $PACKAGE_RES_SHA
dep-pkg: $PACKAGE_DEP_PKG
dep-lib: $PACKAGE_DEP_LIB
dep-upp: $PACKAGE_DEP_UPP
dep-pip: $PACKAGE_DEP_PIP
dep-plm: $PACKAGE_DEP_PLM
bsystem: $PACKAGE_BSYSTEM
binbstd: $PACKAGE_BINBSTD
ppflags: $PACKAGE_PPFLAGS
ccflags: $PACKAGE_CCFLAGS
xxflags: $PACKAGE_XXFLAGS
ldflags: $PACKAGE_LDFLAGS
api-min: $PACKAGE_API_MIN
ltoable: $PACKAGE_LTOABLE
movable: $PACKAGE_MOVABLE
installed: $PACKAGE_INSTALLED
EOF
    } | yq eval '. | with_entries(select(.value != null))'
}

# __info_the_given_available_package_as_shell <PACKAGE-NAME>
  __info_the_given_available_package_as_shell() {
    __load_formula_of_the_given_package "$1"

    while read KEY
    do
        printf "%s='%s'\n" "${PACKAGE_NAME_UPPERCASE_UNDERSCORE}_${KEY}" "$(eval echo \$$KEY)"
    done <<EOF
PACKAGE_NAME
PACKAGE_PKGTYPE
PACKAGE_SUMMARY
PACKAGE_LICENSE
PACKAGE_VERSION
PACKAGE_VERSION_MAJOR
PACKAGE_VERSION_MINOR
PACKAGE_VERSION_PATCH
PACKAGE_VERSION_TWEAK
PACKAGE_WEB_URL
PACKAGE_GIT_URL
PACKAGE_GIT_SHA
PACKAGE_GIT_REF
PACKAGE_GIT_NTH
PACKAGE_SRC_URL
PACKAGE_SRC_URI
PACKAGE_SRC_SHA
PACKAGE_SRC_FILETYPE
PACKAGE_SRC_FILENAME
PACKAGE_SRC_FILEPATH
PACKAGE_FIX_URL
PACKAGE_FIX_URI
PACKAGE_FIX_SHA
PACKAGE_FIX_FILETYPE
PACKAGE_FIX_FILENAME
PACKAGE_FIX_FILEPATH
PACKAGE_RES_URL
PACKAGE_RES_URI
PACKAGE_RES_SHA
PACKAGE_RES_FILETYPE
PACKAGE_RES_FILENAME
PACKAGE_RES_FILEPATH
PACKAGE_BSCRIPT
PACKAGE_BSYSTEM
PACKAGE_BINBSTD
PACKAGE_MOVABLE
PACKAGE_LTOABLE
PACKAGE_USE_GO
PACKAGE_USE_GN
PACKAGE_USE_RAKE
PACKAGE_USE_NINJA
PACKAGE_USE_GMAKE
PACKAGE_USE_CMAKE
PACKAGE_USE_XMAKE
PACKAGE_USE_MESON
PACKAGE_USE_CARGO
PACKAGE_USE_AUTOGENSH
PACKAGE_USE_AUTOTOOLS
PACKAGE_USE_CONFIGURE
PACKAGE_DEP_PKG
PACKAGE_DEP_LIB
PACKAGE_DEP_UPP
PACKAGE_DEP_PIP
PACKAGE_DEP_PLM
PACKAGE_CCFLAGS
PACKAGE_XXFLAGS
PACKAGE_PPFLAGS
PACKAGE_LDFLAGS
PACKAGE_API_MIN
PACKAGE_FORMULA_FILEPATH
PACKAGE_DEVELOPER
EOF
}

# __info_the_given_available_package <PACKAGE-NAME> [--yaml] [--json] [<KEY>]
# __info_the_given_available_package curl
# __info_the_given_available_package curl version
# __info_the_given_available_package curl web-url
  __info_the_given_available_package() {
    case $2 in
        --yaml|'')
            __info_the_given_available_package_as_yaml "$1"
            ;;
        --json)
            __info_the_given_available_package_as_json "$1"
            ;;
        do12345)
            __load_formula_of_the_given_package "$1"
            printf '%s\n' "$PACKAGE_DO12345"
            ;;
        dofetch)
            __load_formula_of_the_given_package "$1"
            printf '%s\n' "$PACKAGE_DOFETCH"
            ;;
        dopatch)
            __load_formula_of_the_given_package "$1"
            printf '%s\n' "$PACKAGE_DOPATCH"
            ;;
        prepare)
            __load_formula_of_the_given_package "$1"
            printf '%s\n' "$PACKAGE_PREPARE"
            ;;
        install)
            __load_formula_of_the_given_package "$1"
            printf '%s\n' "$PACKAGE_DOBUILD"
            ;;
        dotweak)
            __load_formula_of_the_given_package "$1"
            printf '%s\n' "$PACKAGE_DOTWEAK"
            ;;
        movable)
            __load_formula_of_the_given_package "$1"
            printf '%s\n' "$PACKAGE_MOVABLE"
            ;;
        ltoable)
            __load_formula_of_the_given_package "$1"
            printf '%s\n' "$PACKAGE_LTOABLE"
            ;;
        caveats)
            __load_formula_of_the_given_package "$1"
            printf '%s\n' "$PACKAGE_CAVEATS"
            ;;
        developer)
            __load_formula_of_the_given_package "$1"
            printf '%s\n' "$PACKAGE_DEVELOPER"
            ;;
        src-ft)
            __load_formula_of_the_given_package "$1"
            if [ -n "$PACKAGE_SRC_FILETYPE" ] ; then
                printf '%s\n' "$PACKAGE_SRC_FILETYPE"
            fi
            ;;
        src-fp)
            __load_formula_of_the_given_package "$1"
            if [ -n "$PACKAGE_SRC_FILEPATH" ] ; then
                printf '%s\n' "$PACKAGE_SRC_FILEPATH"
            fi
            ;;
        fix-ft)
            __load_formula_of_the_given_package "$1"
            if [ -n "$PACKAGE_FIX_FILETYPE" ] ; then
                printf '%s\n' "$PACKAGE_FIX_FILETYPE"
            fi
            ;;
        fix-fp)
            __load_formula_of_the_given_package "$1"
            if [ -n "$PACKAGE_FIX_FILEPATH" ] ; then
                printf '%s\n' "$PACKAGE_FIX_FILEPATH"
            fi
            ;;
        res-ft)
            __load_formula_of_the_given_package "$1"
            if [ -n "$PACKAGE_RES_FILETYPE" ] ; then
                printf '%s\n' "$PACKAGE_RES_FILETYPE"
            fi
            ;;
        res-fp)
            __load_formula_of_the_given_package "$1"
            if [ -n "$PACKAGE_RES_FILEPATH" ] ; then
                printf '%s\n' "$PACKAGE_RES_FILEPATH"
            fi
            ;;
        *)  __load_formula_of_the_given_package "$1"
            __PACKAGE_GET__KEY__="$(printf '%s\n' "$2" | tr '+-.' '_' | tr a-z A-Z)"
            eval echo \$PACKAGE_$__PACKAGE_GET__KEY__
    esac
}

# __info_the_given_installed_package <PACKAGE-SPEC> [<KEY>]
# __info_the_given_installed_package curl
# __info_the_given_installed_package curl version
# __info_the_given_installed_package curl web-url
  __info_the_given_installed_package() {
    case $2 in
        --yaml|'')
            PACKAGE_SPEC=
            PACKAGE_SPEC="$(inspect_package_spec "$1")"

            if is_package_installed "$PACKAGE_SPEC" ; then
                yq "$NDKPKG_PACKAGE_INSTALLED_ROOT/$PACKAGE_SPEC/.ndk-pkg/RECEIPT.yml"
            else
                abort 1 "package '$PACKAGE_SPEC' is not installed."
            fi
            ;;
        --json)
            __info_the_given_installed_package_as_json "$1"
            ;;
        --prefix)
            PACKAGE_SPEC=
            PACKAGE_SPEC="$(inspect_package_spec "$1")"

            if is_package_installed "$PACKAGE_SPEC" ; then
                PACKAGE_INSTALLED_DIR="$NDKPKG_PACKAGE_INSTALLED_ROOT/$PACKAGE_SPEC"
                printf '%s\n' "$PACKAGE_INSTALLED_DIR"
            else
                abort 1 "package '$PACKAGE_SPEC' is not installed."
            fi
            ;;
        --files)
            PACKAGE_SPEC=
            PACKAGE_SPEC="$(inspect_package_spec "$1")"

            if is_package_installed "$PACKAGE_SPEC" ; then
                cut -d '|' -f3 "$NDKPKG_PACKAGE_INSTALLED_ROOT/$PACKAGE_SPEC/.ndk-pkg/MANIFEST.txt"
            else
                abort 1 "package '$PACKAGE_SPEC' is not installed."
            fi
            ;;
        builtat)
            __load_receipt_of_the_given_package "$1"
            printf '%s\n' "$RECEIPT_PACKAGE_BUILTAT"
            ;;
        builtat-rfc-3339)
            __load_receipt_of_the_given_package "$1"
            date -d "@$RECEIPT_PACKAGE_BUILTAT" '+%Y-%m-%d %H:%M:%S%:z'
            ;;
        builtat-iso-8601)
            __load_receipt_of_the_given_package "$1"
            date -d "@$RECEIPT_PACKAGE_BUILTAT" '+%Y-%m-%dT%H:%M:%S%:z'
            ;;
        builtat-rfc-3339-utc)
            __load_receipt_of_the_given_package "$1"
            date -u -d "@$RECEIPT_PACKAGE_BUILTAT" '+%Y-%m-%d %H:%M:%S%:z'
            ;;
        builtat-iso-8601-utc)
            __load_receipt_of_the_given_package "$1"
            date -u -d "@$RECEIPT_PACKAGE_BUILTAT" '+%Y-%m-%dT%H:%M:%SZ'
            ;;
        *)  __load_receipt_of_the_given_package "$1"
            __PACKAGE_GET__KEY__="$(printf '%s\n' "$2" | tr '+-.' '_' | tr a-z A-Z)"
            eval echo \$RECEIPT_PACKAGE_$__PACKAGE_GET__KEY__
    esac
}

# __info_the_given_installed_package_as_json <PACKAGE-NAME|PACKAGE_SPEC>
  __info_the_given_installed_package_as_json() {
    __load_receipt_of_the_given_package "$1"

    jq  --null-input \
        --arg pkgname "$RECEIPT_PACKAGE_PKGNAME" \
        --arg pkgtype "$RECEIPT_PACKAGE_PKGTYPE" \
        --arg version "$RECEIPT_PACKAGE_VERSION" \
        --arg summary "$RECEIPT_PACKAGE_SUMMARY" \
        --arg license "$RECEIPT_PACKAGE_LICENSE" \
        --arg web_url "$RECEIPT_PACKAGE_WEB_URL" \
        --arg git_url "$RECEIPT_PACKAGE_GIT_URL" \
        --arg git_sha "$RECEIPT_PACKAGE_GIT_SHA" \
        --arg git_ref "$RECEIPT_PACKAGE_GIT_REF" \
        --arg git_nth "$RECEIPT_PACKAGE_GIT_NTH" \
        --arg src_url "$RECEIPT_PACKAGE_SRC_URL" \
        --arg src_uri "$RECEIPT_PACKAGE_SRC_URI" \
        --arg src_sha "$RECEIPT_PACKAGE_SRC_SHA" \
        --arg fix_url "$RECEIPT_PACKAGE_FIX_URL" \
        --arg fix_uri "$RECEIPT_PACKAGE_FIX_URI" \
        --arg fix_sha "$RECEIPT_PACKAGE_FIX_SHA" \
        --arg res_url "$RECEIPT_PACKAGE_RES_URL" \
        --arg res_uri "$RECEIPT_PACKAGE_RES_URI" \
        --arg res_sha "$RECEIPT_PACKAGE_RES_SHA" \
        --arg patches "$RECEIPT_PACKAGE_PATCHES" \
        --arg reslist "$RECEIPT_PACKAGE_RESLIST" \
        --arg dep_pkg "$RECEIPT_PACKAGE_DEP_PKG" \
        --arg dep_lib "$RECEIPT_PACKAGE_DEP_LIB" \
        --arg dep_upp "$RECEIPT_PACKAGE_DEP_UPP" \
        --arg dep_pip "$RECEIPT_PACKAGE_DEP_PIP" \
        --arg dep_plm "$RECEIPT_PACKAGE_DEP_PLM" \
        --arg dofetch "$RECEIPT_PACKAGE_DOFETCH" \
        --arg do12345 "$RECEIPT_PACKAGE_DO12345" \
        --arg dopatch "$RECEIPT_PACKAGE_DOPATCH" \
        --arg prepare "$RECEIPT_PACKAGE_PREPARE" \
        --arg install "$RECEIPT_PACKAGE_DOBUILD" \
        --arg dotweak "$RECEIPT_PACKAGE_DOTWEAK" \
        --arg movable "$RECEIPT_PACKAGE_MOVABLE" \
        --arg ltoable "$RECEIPT_PACKAGE_LTOABLE" \
        --arg caveats "$RECEIPT_PACKAGE_CAVEATS" \
        --arg bsystem "$RECEIPT_PACKAGE_BSYSTEM" \
        --arg binbstd "$RECEIPT_PACKAGE_BINBSTD" \
        --arg ccflags "$RECEIPT_PACKAGE_CCFLAGS" \
        --arg xxflags "$RECEIPT_PACKAGE_XXFLAGS" \
        --arg ppflags "$RECEIPT_PACKAGE_PPFLAGS" \
        --arg ldflags "$RECEIPT_PACKAGE_LDFLAGS" \
        --arg developer "$RECEIPT_PACKAGE_DEVELOPER" \
        --arg builtby "$RECEIPT_PACKAGE_BUILTBY" \
        --arg builtat "$RECEIPT_PACKAGE_BUILTAT" \
        --arg builtfor "$RECEIPT_PACKAGE_BUILTFOR" \
'{
    "pkgname":$pkgname,
    "pkgtype":$pkgtype,
    "version":$version,
    "license":$license,
    "summary":$summary,
    "web-url":$web_url,
    "git-url":$git_url,
    "git-sha":$git_sha,
    "git-ref":$git_ref,
    "git-nth":$git_nth,
    "src-url":$src_url,
    "src-uri":$src_uri,
    "src-sha":$src_sha,
    "fix-url":$fix_url,
    "fix-uri":$fix_uri,
    "fix-sha":$fix_sha,
    "res-url":$res_url,
    "res-uri":$res_uri,
    "res-sha":$res_sha,
    "patches":$patches,
    "reslist":$reslist,
    "dep-pkg":$dep_pkg,
    "dep-lib":$dep_lib,
    "dep-upp":$dep_upp,
    "dep-pip":$dep_pip,
    "dep-plm":$dep_plm,
    "bsystem":$bsystem,
    "binbstd":$binbstd,
    "ccflags":$ccflags,
    "xxflags":$xxflags,
    "ppflags":$ppflags,
    "ldflags":$ldflags,
    "developer":$developer,
    "dofetch":$dofetch,
    "do12345":$do12345,
    "dopatch":$dopatch,
    "prepare":$prepare,
    "install":$install,
    "dotweak":$dotweak,
    "movable":$movable,
    "ltoable":$ltoable,
    "caveats":$caveats,
    "builtby":$builtby,
    "builtat":$builtat,
    "builtfor":$builtfor
}' | jq 'with_entries(select(.value != ""))'
}

# }}}
##############################################################################
# {{{ ndk-pkg fetch

__fetch_resources_of_the_given_package() {
    if [ -z "$1" ] ; then
        abort 1 "__fetch_resources_of_the_given_package <PACKAGE-NAME>, <PACKAGE-NAME> is unspecified."
    fi

    __load_formula_of_the_given_package "$1"

    if [ -n "$PACKAGE_SRC_URL" ] ; then
        case $PACKAGE_SRC_URL in
            dir://*)
                note "$PACKAGE_SRC_URL is local path, no need to fetch."
                return 0
                ;;
            file://*)
                note "$PACKAGE_SRC_URL is local path, no need to fetch."
                return 0
                ;;
            *)  wfetch "$PACKAGE_SRC_URL" --uri="$PACKAGE_SRC_URI" --sha256="$PACKAGE_SRC_SHA" -o "$PACKAGE_SRC_FILEPATH"
        esac
    elif [ -n "$PACKAGE_GIT_URL" ] ; then
        unset GIT_FETCH_URL

        if [ -z "$NDKPKG_URL_TRANSFORM" ] ; then
            GIT_FETCH_URL="$PACKAGE_GIT_URL"
        else
            GIT_FETCH_URL="$("$NDKPKG_URL_TRANSFORM" "$PACKAGE_GIT_URL")" || return 1
        fi

        if [ -z "$PACKAGE_GIT_SHA" ] ; then
            if [ -z "$PACKAGE_GIT_REF" ] ; then
                GIT_BRANCH_NAME=master
                GIT_REF_SPEC="+HEAD:refs/remotes/origin/master"
            else
                GIT_BRANCH_NAME="$(basename "$PACKAGE_GIT_REF")"
                GIT_REF_SPEC="+$PACKAGE_GIT_REF:refs/remotes/origin/$GIT_BRANCH_NAME"
            fi
        else
            GIT_BRANCH_NAME=master
            GIT_REF_SPEC="+$PACKAGE_GIT_SHA:refs/remotes/origin/master"
        fi

        if [ -z "$PACKAGE_GIT_NTH" ] ; then
            PACKAGE_GIT_NTH=1
        fi

        if [ "$PACKAGE_GIT_NTH" -eq 0 ] ; then
            if [ -f "$PACKAGE_SRC_FILEPATH/.git/shallow" ] ; then
                GIT_FETCH_EXTRA_OPTIONS='--unshallow'
            else
                GIT_FETCH_EXTRA_OPTIONS=
            fi
        else
            GIT_FETCH_EXTRA_OPTIONS="--depth=$PACKAGE_GIT_NTH"
        fi

        SESSION_DIR="$NDKPKG_HOME/run/$$"

        run rm -rf     "$SESSION_DIR"
        run install -d "$SESSION_DIR"
        run cd         "$SESSION_DIR"

        run git -c init.defaultBranch=master init
        run git remote add origin "$GIT_FETCH_URL"
        run git -c protocol.version=2 fetch --progress $GIT_FETCH_EXTRA_OPTIONS origin "$GIT_REF_SPEC"
        run git checkout --progress --force -B "$GIT_BRANCH_NAME" "refs/remotes/origin/$GIT_BRANCH_NAME"

        git_submodule_update_recursive

        rm -rf "$SESSION_DIR"
    fi

    if [ -n    "$PACKAGE_FIX_URL" ] ; then
        wfetch "$PACKAGE_FIX_URL" --uri="$PACKAGE_FIX_URI" --sha256="$PACKAGE_FIX_SHA" -o "$PACKAGE_FIX_FILEPATH"
    fi

    if [ -n    "$PACKAGE_RES_URL" ] ; then
        wfetch "$PACKAGE_RES_URL" --uri="$PACKAGE_RES_URI" --sha256="$PACKAGE_RES_SHA" -o "$PACKAGE_RES_FILEPATH"
    fi
}

# }}}
##############################################################################
# {{{ ndk-pkg tree

# __tree_the_given_installed_package <PACKAGE-SPEC>
  __tree_the_given_installed_package() {
    PACKAGE_SPEC=
    PACKAGE_SPEC="$(inspect_package_spec "$1")"

    if is_package_installed "$PACKAGE_SPEC" ; then
        PACKAGE_INSTALLED_DIR="$NDKPKG_PACKAGE_INSTALLED_ROOT/$PACKAGE_SPEC"
    else
        abort 1 "package '$PACKAGE_SPEC' is not installed."
    fi

    shift

    run tree "$@" "$PACKAGE_INSTALLED_DIR"
}

# }}}
##############################################################################
# {{{ ndk-pkg logs

# __logs_the_given_installed_package <PACKAGE-SPEC>
  __logs_the_given_installed_package() {
    PACKAGE_SPEC="$(inspect_package_spec "$1")"

    if is_package_installed "$PACKAGE_SPEC" ; then
        PACKAGE_INSTALLED_DIR="$NDKPKG_PACKAGE_INSTALLED_ROOT/$PACKAGE_SPEC"
    else
        abort 1 "package '$PACKAGE_SPEC' is not installed."
    fi

    cd "$PACKAGE_INSTALLED_DIR/.ndk-pkg"

    fzf --preview='bat --color=always --theme=Dracula {}' --preview-window='right:75%'
}

# }}}
##############################################################################
# {{{ ndk-pkg bundle

# __bundle_the_given_installed_package <PACKAGE-SPEC> [<OUTPUT-DIR>][<OUTPUT-FILENAME-PREFIX>]<BUNDLE-TYPE>] [--exclude <EXCLUDE-PATH>] [-K] [--portable]
  __bundle_the_given_installed_package() {
    __load_receipt_of_the_given_package "$1"

    #######################################################

    unset OUTPUT_DIR
    unset OUTPUT_PATH
    unset OUTPUT_TYPE
    unset OUTPUT_NAME

    case $2 in
        '') abort 1 "$NDKPKG_ARG0 bundle <PACKAGE-SPEC> [<OUTPUT-DIR>][<OUTPUT-FILENAME-PREFIX>]<BUNDLE-TYPE>], forth argument is unspecified."
            ;;
        */*)
            OUTPUT_DIR="${2%/*}"
            [ -z "$OUTPUT_DIR" ] && OUTPUT_DIR=/
            OUTPUT_NAME="${2##*/}"
            ;;
        *)  OUTPUT_NAME="$2"
    esac

    case $OUTPUT_NAME in
        '') abort 1 "$NDKPKG_ARG0 bundle <PACKAGE-SPEC> [<OUTPUT-DIR>][<OUTPUT-FILENAME-PREFIX>]<BUNDLE-TYPE>, <BUNDLE-TYPE> is unspecified."
            ;;
        *.tar.gz)
            OUTPUT_TYPE=.tar.gz
            ;;
        *.tar.xz)
            OUTPUT_TYPE=.tar.xz
            ;;
        *.tar.lz)
            OUTPUT_TYPE=.tar.lz
            ;;
        *.tar.bz2)
            OUTPUT_TYPE=.tar.bz2
            ;;
        *.zip)
            OUTPUT_TYPE=.zip
            ;;
        *)  abort 1 "$NDKPKG_ARG0 bundle <PACKAGE-SPEC> [<OUTPUT-DIR>][<OUTPUT-FILENAME-PREFIX>]<BUNDLE-TYPE>, invalid forth argument: $2"
    esac

    if [ "$OUTPUT_NAME" = "$OUTPUT_TYPE" ] ; then
        if [ -z "$OUTPUT_DIR"  ] ; then
            OUTPUT_PATH=.
        else
            OUTPUT_PATH="$OUTPUT_DIR/"
        fi
    else
        OUTPUT_PATH="$2"
    fi

    #######################################################

    shift 2

    unset REQUEST_TO_KEEP_SESSION_DIR

    unset EXCLUDES

    unset PORTABLE

    while [ -n "$1" ]
    do
        case $1 in
            -K) REQUEST_TO_KEEP_SESSION_DIR=1
                ;;
            --exclude)
                shift
                if [ -z "$1" ] ; then
                    abort 1 "$NDKPKG_ARG0 bundle <PACKAGE-SPEC> [<OUTPUT-DIR>][<OUTPUT-FILENAME-PREFIX>]<BUNDLE-TYPE>] [--exclude <PATH>], --exclude option is specified but <PATH> is unspecified."
                else
                    EXCLUDES="$EXCLUDES $1"
                fi
                ;;
            --portable)
                PORTABLE=1
                ;;
            *)  abort 1 "$NDKPKG_ARG0 bundle <PACKAGE-SPEC> [<OUTPUT-DIR>][<OUTPUT-FILENAME-PREFIX>]<BUNDLE-TYPE>], unrecognized option: $1"
        esac
        shift
    done

    #######################################################

    OLDCWD="$PWD"

    SESSION_DIR="$NDKPKG_HOME/run/$$"

    run rm -rf     "$SESSION_DIR"
    run install -d "$SESSION_DIR"
    run cd         "$SESSION_DIR"

    #######################################################

    if [ -n "$EXCLUDES" ] || [ "$PORTABLE" = 1 ] ; then
        run install -d bundle.d/

        run cp -r "$PACKAGE_INSTALLED_DIR/." bundle.d/

        for EXCLUDE in $EXCLUDES
        do
            run rm -rf "bundle.d/$EXCLUDE"
        done
    else
        run ln -s "$PACKAGE_INSTALLED_DIR" bundle.d
    fi

    #######################################################

    if [ "$PORTABLE" = 1 ] ; then
        FILEPATHs=

        find bundle.d -type f -not -path 'bundle.d/.ndk-pkg/*' > fs.txt

        while read -r FILEPATH
        do
            FILEMAGIC="$(xxd -u -p -l 4 "$FILEPATH")"

            [ "$FILEMAGIC" = '7F454C46' ] || continue

            ELFTYPE="$(xxd -u -p -l 2 -s 16 "$FILEPATH")"

            case $ELFTYPE in
                0200)
                    if [ -f "$FILEPATH.c" ] || [ -n "$RECEIPT_PACKAGE_BINDENV" ] ; then
                        FILEPATHs="$FILEPATHs $FILEPATH"
                    fi
                    ;;
                0300)
                    DYNAMIC_LOADER_FILEPATH="$(patchelf --print-interpreter "$FILEPATH" 2>/dev/null || true)"

                    if [ -n "$DYNAMIC_LOADER_FILEPATH" ] ; then
                        FILEPATHs="$FILEPATHs $FILEPATH"
                    fi
            esac
        done < fs.txt

        if [ -n "$FILEPATHs" ] ; then
            setup_android_ndk_env '' "$ANDROID_NDK_HOME"

            if [ "$RECEIPT_PACKAGE_BUILTFOR_PLATFORM_ARCH" = armv7a ] ; then
                TARGET_TRIPLE='armv7a-linux-androideabi'
            else
                TARGET_TRIPLE="$RECEIPT_PACKAGE_BUILTFOR_PLATFORM_ARCH-linux-android"
            fi

            ANDROID_NDK_CC="$ANDROID_NDK_CC --target=${TARGET_TRIPLE}${ANDROID_NDK_SUPPORTED_MAX_SDK_API_LEVEL} --sysroot=$ANDROID_NDK_SYSROOT"

            for FILEPATH in $FILEPATHs
            do
                [ -f "$FILEPATH.c" ] || __generate_wrapper_c_source_file

                run mv "$FILEPATH" "$FILEPATH.exe"
                run "$ANDROID_NDK_CC" -static -Os -s -flto -o "$FILEPATH" "$FILEPATH.c"
            done
        fi
    fi

    #######################################################

    unset OUTPUT_FILENAME_NEED_ANDROID_API_LEVEL

    if [ -d bundle.d/lib ] ; then
        if [ "$OUTPUT_FILENAME_NEED_ANDROID_API_LEVEL" != 1 ] ; then
            for FILEPATH in $(find bundle.d/lib -type f -name 'lib*.a' -print -quit)
            do
                OUTPUT_FILENAME_NEED_ANDROID_API_LEVEL=1
            done
        fi

        if [ "$OUTPUT_FILENAME_NEED_ANDROID_API_LEVEL" != 1 ] ; then
            for FILEPATH in $(find bundle.d/lib -type f -name 'lib*.so' -print -quit)
            do
                OUTPUT_FILENAME_NEED_ANDROID_API_LEVEL=1
            done
        fi

        if [ "$OUTPUT_FILENAME_NEED_ANDROID_API_LEVEL" != 1 ] ; then
            for FILEPATH in $(find bundle.d/lib -type f -name '*.o' -print -quit)
            do
                OUTPUT_FILENAME_NEED_ANDROID_API_LEVEL=1
            done
        fi
    fi

    if [ "$OUTPUT_FILENAME_NEED_ANDROID_API_LEVEL" != 1 ] ; then
        for d in bin sbin libexec
        do
            if [ -d "bundle.d/$d" ] ; then
                for FILEPATH in $(find "bundle.d/$d" -type f)
                do
                    FILEMAGIC="$(xxd -u -p -l 4 "$FILEPATH")"

                    if [ "$FILEMAGIC" = '7F454C46' ] ; then
                        # http://www.sco.com/developers/gabi/latest/ch4.eheader.html
                        DYNAMIC_LINKER_PATH="$(patchelf --print-interpreter "$FILEPATH" 2>/dev/null || true)"

                        if [ -n "$DYNAMIC_LINKER_PATH" ] ; then
                            OUTPUT_FILENAME_NEED_ANDROID_API_LEVEL=1
                            break
                        fi
                    fi
                done
            fi
        done
    fi

    if [ "$OUTPUT_FILENAME_NEED_ANDROID_API_LEVEL" != 1 ] ; then
        for FILEPATH in $(find bundle.d/ -type f -name '*.a' -print -quit)
        do
            OUTPUT_FILENAME_NEED_ANDROID_API_LEVEL=1
        done
    fi

    if [ "$OUTPUT_FILENAME_NEED_ANDROID_API_LEVEL" = 1 ] ; then
        BUNDLE_DIR_NAME="${RECEIPT_PACKAGE_PKGNAME%@*}-$RECEIPT_PACKAGE_VERSION-$RECEIPT_PACKAGE_BUILTFOR_PLATFORM"
    else
        BUNDLE_DIR_NAME="${RECEIPT_PACKAGE_PKGNAME%@*}-$RECEIPT_PACKAGE_VERSION-$RECEIPT_PACKAGE_BUILTFOR_PLATFORM_NAME-$RECEIPT_PACKAGE_BUILTFOR_PLATFORM_ARCH"
    fi

    BUNDLE_DIR_NAME="$BUNDLE_DIR_NAME.$RECEIPT_PACKAGE_PROFILE"

    OUTPUT_FILENAME="$BUNDLE_DIR_NAME$OUTPUT_TYPE"

    #######################################################

    run mv bundle.d "$BUNDLE_DIR_NAME"

    run bsdtar cvaf "$OUTPUT_FILENAME" "$BUNDLE_DIR_NAME/*" "$BUNDLE_DIR_NAME/.ndk-pkg"

    run du -sh "$OUTPUT_FILENAME"

    run cd "$OLDCWD"

    if [ -n "$OUTPUT_DIR" ] && [ "$OUTPUT_DIR" != . ] && [ "$OUTPUT_DIR" != .. ] && [ "$OUTPUT_DIR" != / ] && [ ! -d "$OUTPUT_DIR" ] ; then
        run install -d "$OUTPUT_DIR"
    fi

    run mv "$SESSION_DIR/$OUTPUT_FILENAME" "$OUTPUT_PATH"

    #######################################################

    if [ "$REQUEST_TO_KEEP_SESSION_DIR" = 1 ] ; then
        echo
        note "the session directory '$SESSION_DIR' is not deleted as -K option is specified."
    else
        run rm -rf "$SESSION_DIR"
    fi
}

__generate_wrapper_c_source_file() {
    cat > "$FILEPATH.c" <<EOF
#include <stdio.h>
#include <stdlib.h>

#include <unistd.h>
#include <limits.h>

int main(int argc, char* argv[]) {
    char selfExePath[PATH_MAX];

    int n = readlink("/proc/self/exe", selfExePath, PATH_MAX);

    if (n == -1) {
        perror("/proc/self/exe");
        return 1;
    }

    selfExePath[n] = '\\0';

    ////////////////////////////////////////////////////

    const char * s = ".exe";

    int j;

    for (j = 0; s[j] != '\0'; j++);

    char realExePath[n + j + 1];

    int slashIndex = -1;

    int i;

    for (i = 0; i < n; i++) {
        realExePath[i] = selfExePath[i];

        if (selfExePath[i] == '/') {
            slashIndex = i;
        }
    }

    char * p = realExePath + n;

    for (i = 0; i <= j; i++) {
        p[i] = s[i];
    }
EOF

    ####################################

    I=0

    for LINE in $RECEIPT_PACKAGE_BINDENV
    do
        VALUE="${LINE#*=}"

        case $VALUE in
            %s/*)
                I="$(($I + 1))"
                KEY="${LINE%%=*}"
                VALUE="$(printf "$VALUE\n" 'bundle.d')"
                VALUE_RELATIVE_TO_SELF_EXE_PATH="$(realpath -m --relative-to="${FILEPATH%/*}" "$VALUE")"

                cat >> "$FILEPATH.c" <<EOF

    ////////////////////////////////////////////////////

    p = getenv("$KEY");

    if (p == NULL || p[0] == '\0') {
        s = "$VALUE_RELATIVE_TO_SELF_EXE_PATH";

        for (j = 0; s[j] != '\0'; j++);

        char pathBuf[slashIndex + j + 1];

        for (i = 0; i <= slashIndex; i++) {
            pathBuf[i] = selfExePath[i];
        }

        p = pathBuf + slashIndex + 1;

        for (i = 0U; i <= j; i++) {
            p[i] = s[i];
        }

        if (setenv("$KEY", pathBuf, 1) != 0) {
            perror("$KEY");
            return 10;
        }
    }
EOF
                ;;
            *)  cat >> "$FILEPATH.c" <<EOF

    ////////////////////////////////////////////////////

    if (putenv("$LINE") != 0) {
        perror(NULL);
        return 10;
    }
EOF
        esac
    done

    ####################################

    cat >> "$FILEPATH.c" <<EOF

    ////////////////////////////////////////////////////

    argv[0] = realExePath;

    execv (realExePath, argv);
    perror(realExePath);
    return 255;
}
EOF
}

# }}}
##############################################################################
# {{{ ndk-pkg export

# https://developer.android.com/studio/projects/android-library#aar-contents
# https://google.github.io/prefab/#package-structure
#
# libz-1.2.13.aar
# ├── AndroidManifest.xml
# ├── META-INF
# │   ├── FAQ
# │   ├── LICENSE
# │   ├── MANIFEST.txt
# │   ├── README
# │   ├── README.ndk-pkg
# │   └── RECEIPT.yml
# └── prefab
#     ├── prefab.json
#     └── modules
#         ├── headers
#         │   └── include
#         │       ├── zconf.h
#         │       └── zlib.h
#         ├── libz.a
#         │   ├── module.josn
#         │   ├── include
#         │   │   ├── zconf.h
#         │   │   └── zlib.h
#         │   └── libs
#         │       ├── android.arm64-v8a
#         │       │   ├── abi.json
#         │       │   └── libz.a
#         │       ├── android.armeabi-v7a
#         │       │   ├── abi.json
#         │       │   └── libz.a
#         │       ├── android.x86
#         │       │   ├── abi.json
#         │       │   └── libz.a
#         │       └── android.x86_64
#         │           ├── abi.json
#         │           └── libz.a
#         └── libz.so
#             ├── module.josn
#             ├── include
#             │   ├── zconf.h
#             │   └── zlib.h
#             └── libs
#                 ├── android.arm64-v8a
#                 │   ├── abi.json
#                 │   └── libz.so
#                 ├── android.armeabi-v7a
#                 │   ├── abi.json
#                 │   └── libz.so
#                 ├── android.x86
#                 │   ├── abi.json
#                 │   └── libz.so
#                 └── android.x86_64
#                     ├── abi.json
#                     └── libz.so
#
# __export_google_prefab_aar_for_the_given_installed_packages android-<ANDROID-API>-<ANDROID-ABIs>/<PACKAGE-NAME> [--ndk-home=<ANDROID-NDK-HOME>] [-o <OUTPUT-PATH>] [-K]

  __export_google_prefab_aar_for_the_given_installed_packages() {
    unset PACKAGE_NAME

    unset TARGET_PLATFORM_VERS
    unset TARGET_PLATFORM_ABIS

    case $1 in
        android-[1-9][0-9]-*/*)
            PACKAGE_NAME="${1#*/}"

            if [ -z "$PACKAGE_NAME" ] ; then
                abort 1 "invalid package spec: $1\n    package name is unspecifed."
            elif printf '%s\n' "$PACKAGE_NAME" | grep -q -E '^[A-Za-z0-9+-_.@]{1,50}$' ; then
                :
            else
                abort 1 "invalid package spec: $1\n    package name must match the regular expression pattern: ^[A-Za-z0-9+-_.@]{1,50}$"
            fi

            TARGET_PLATFORM_SPEC="${1%%/*}"
            TARGET_PLATFORM_VERS="$(printf '%s\n' "$TARGET_PLATFORM_SPEC" | cut -d- -f2)"
            TARGET_PLATFORM_ABIS="$(printf '%s\n' "$TARGET_PLATFORM_SPEC" | cut -c 12- | tr ',' ' ')"

            for TARGET_PLATFORM_ABI in $TARGET_PLATFORM_ABIS
            do
                case $TARGET_PLATFORM_ABI in
                    armeabi-v7a|arm64-v8a|x86|x86_64)
                        ;;
                    *)  abort 1 "invalid package spec: $1\n    unsupported abi: $TARGET_PLATFORM_ABI"
                esac
            done
            ;;
        *)  abort 1 "invalid package spec: $1"
    esac

    #########################################################################################

    shift

    unset ANDROID_NDK_HOME
    unset ANDROID_NDK_REVISION

    unset OUTPUT_PATH

    unset REQUEST_TO_KEEP_SESSION_DIR

    while [ -n "$1" ]
    do
        case $1 in
            --ndk-home=*)
                ANDROID_NDK_HOME="${1#*=}"
                ;;
            -o) shift
                OUTPUT_PATH="$1"
                ;;
            -K) REQUEST_TO_KEEP_SESSION_DIR=1
                ;;
        esac
        shift
    done

    #########################################################################################

    PACKAGE_SPEC="android-$TARGET_PLATFORM_VERS-$TARGET_PLATFORM_ABI/$PACKAGE_NAME"

    __load_receipt_of_the_given_package "$PACKAGE_SPEC"

    #########################################################################################

    setup_android_ndk_env "$ANDROID_NDK_REVISION" "$ANDROID_NDK_HOME"

    #########################################################################################

    SESSION_DIR="$NDKPKG_HOME/run/$$"

    step "create the session directory and change to it"
    run rm -rf     "$SESSION_DIR"
    run install -d "$SESSION_DIR"
    run cd         "$SESSION_DIR"

    #########################################################################################

    PACKAGE_INCLUDE_DIR="$PACKAGE_INSTALLED_DIR/include"

    if [ ! -d "$PACKAGE_INCLUDE_DIR" ] ; then
        abort 10 "unable to be exported as google prefab due to there is no C/C++ header files in package $PACKAGE_SPEC"
    fi

    #########################################################################################

    # For compatibility with CMake, versions must be specified as major[.minor[.patch[.tweak]]] with all components being numeric.

    if [ -z "$RECEIPT_PACKAGE_VERSION" ] ; then
        PREFAB_PACKAGE_VERS="$(date -u -d "@$RECEIPT_PACKAGE_BUILTAT" '+%Y.%m.%d')"
    else
        unset SED_E

        I=0

        for CHAR in a b c d e f g h i j k l m n o p q r s t u v w x y z
        do
            I=$(expr "$I" + 1)
            SED_E="$SED_E -e s|$CHAR|.$I|g"
        done

        # r3060
        # 1.4.rc5
        # 2022-03-28
        # 2.4+20151223
        # 1.1.1n
        # 9e
        # 2.8.9rel.1
        # 0.14.1-beta
        # 0.99.beta20
        # 3.0-11
        # 1.4g
        # 0.15.2e
        PREFAB_PACKAGE_VERS="$(printf '%s\n' "$RECEIPT_PACKAGE_VERSION" | tr +- . | sed -e 's|beta|2|' -e 's|rel||' -e 's|rc|.|' -e 's|^r||' $SED_E)"

        printf '%s\n' "$PREFAB_PACKAGE_VERS" | {
            grep -q '[0-9]*' ||
            grep -q '[0-9]*\.[0-9]*' ||
            grep -q '[0-9]*\.[0-9]*\.[0-9]*' ||
            grep -q '[0-9]*\.[0-9]*\.[0-9]*\.[0-9]*'
        } || abort 1 "version[$PREFAB_PACKAGE_VERS] not expected."
    fi

    #########################################################################################

    PREFAB_PACKAGE_NAME="${PACKAGE_NAME%@*}"

    #########################################################################################

    # https://google.github.io/prefab/#package-metadata
    install -d prefab
    cat > prefab/prefab.json <<EOF
{
  "schema_version": 2,
  "name": "$PREFAB_PACKAGE_NAME",
  "version": "$PREFAB_PACKAGE_VERS",
  "dependencies": [ ]
}
EOF

    #########################################################################################

    step "create META-INF"
    run cp -r "$PACKAGE_INSTALLED_DIR/.ndk-pkg" META-INF
    cat > META-INF/README.ndk-pkg <<EOF
packed by ndk-pkg-$NDKPKG_VERSION in $(date -u -d "@$TIMESTAMP_UNIX" '+%Y-%m-%d %H:%M:%SZ')

For more details, please refer to https://github.com/leleliu008/ndk-pkg
EOF

    #########################################################################################

    unset JAVA_PACKAGE_NAME

    # java package name characters [a-z0-9_.]
    JAVA_PACKAGE_NAME="$(printf '%s\n' "$PREFAB_PACKAGE_NAME" | tr '+-.' '_' | tr A-Z a-z)"

    step "create AndroidManifest.xml"
    tee AndroidManifest.xml <<EOF
<?xml version="1.0" encoding="utf-8"?>
<manifest
    xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.fpliu.ndk.pkg.prefab.android$TARGET_PLATFORM_VERS.$JAVA_PACKAGE_NAME">

    <uses-sdk android:minSdkVersion="$TARGET_PLATFORM_VERS" />

</manifest>
EOF

    #########################################################################################

    step "create the header-only module"
    run install -d prefab/modules/headers
    run cp -r "$PACKAGE_INCLUDE_DIR" prefab/modules/headers/

    #########################################################################################

    PACKAGE_LIBRARY_DIR="$PACKAGE_INSTALLED_DIR/lib"

    unset LIBRARIes

    if [ -d "$PACKAGE_LIBRARY_DIR" ] ; then
        LIBRARIes="$(find -L "$PACKAGE_LIBRARY_DIR" -maxdepth 1 -mindepth 1 -type f \( -name 'lib*.a' -or -name 'lib*.so' \) -printf '%f:%l\n')"
    fi

    for LIBRARY in $LIBRARIes
    do
        LIBRARY_FILENAME="${LIBRARY%:*}"

        LIBRARY_REALNAME="${LIBRARY#*:}"

        if [ -z "$LIBRARY_REALNAME" ] ; then
            LIBRARY_REALNAME="$LIBRARY_FILENAME"
        fi

        case $LIBRARY_FILENAME in
            *.a)  LIBRARY_FILENAME_PREFIX="${LIBRARY_FILENAME%.a}"  ; IS_STATIC_LIBRARY=true  ;;
            *.so) LIBRARY_FILENAME_PREFIX="${LIBRARY_FILENAME%.so}" ; IS_STATIC_LIBRARY=false ;;
        esac

        MODULE_DIR="prefab/modules/$LIBRARY_FILENAME"

        step "create module : $LIBRARY_FILENAME"

        run install -d "$MODULE_DIR"

        cat > "$MODULE_DIR/module.json" <<EOF
{
  "export_libraries": [],
  "android": {
    "library_name": "$LIBRARY_FILENAME_PREFIX",
    "export_libraries": []
  }
}
EOF

        for TARGET_PLATFORM_ABI in $TARGET_PLATFORM_ABIS
        do
            PACKAGE_SPEC="android-$TARGET_PLATFORM_VERS-$TARGET_PLATFORM_ABI/$PACKAGE_NAME"

            __load_receipt_of_the_given_package "$PACKAGE_SPEC"

            PACKAGE_INCLUDE_DIR="$PACKAGE_INSTALLED_DIR/include"
            PACKAGE_LIBRARY_DIR="$PACKAGE_INSTALLED_DIR/lib"

            LIBRARY_FILEPATH="$PACKAGE_LIBRARY_DIR/$LIBRARY_REALNAME"

            #################################################################

            ABI_DIR="$MODULE_DIR/libs/android.$TARGET_PLATFORM_ABI"

            run install -d "$ABI_DIR"

            run cp -L -r "$PACKAGE_INCLUDE_DIR" "$ABI_DIR/"

            run cp -L "$LIBRARY_FILEPATH" "$ABI_DIR/$LIBRARY_FILENAME"

            #################################################################

            STL=none

            # https://github.com/google/prefab/blob/master/api/src/main/kotlin/com/google/prefab/api/Android.kt#L202
            if [ "$IS_STATIC_LIBRARY" = true ] ; then
                if   "$ANDROID_NDK_NM" "$LIBRARY_FILEPATH" | grep -q 'T __cxa_' ; then
                    abort 1 "libc++_static.a has been merged into $LIBRARY_FILEPATH, this may cause problems. For more details, please refer to https://developer.android.com/ndk/guides/cpp-support"
                elif "$ANDROID_NDK_NM" "$LIBRARY_FILEPATH" | grep -q 'U __cxa_' ; then
                    STL=c++_shared
                fi
            else
                # http://www.sco.com/developers/gabi/latest/ch5.dynamic.html#dynamic_section
                SONAME="$(patchelf --print-soname "$LIBRARY_FILEPATH")"

                # On Android, a so file must have the SONAME
                # https://github.com/android/ndk/issues/1865
                # https://android.googlesource.com/platform/bionic/+/master/android-changes-for-ndk-developers.md
                if [ -z "$SONAME" ] ; then
                    abort 1 "unexpected so file: $LIBRARY_FILEPATH\n    SONAME: not set"
                fi

                if [ "$SONAME" != "$LIBRARY_FILENAME" ] ; then
                    abort 1 "unexpected so file: $LIBRARY_FILEPATH\n    SONAME: $SONAME"
                fi

                DT_NEEDED_LIST="$(patchelf --print-needed "$LIBRARY_FILEPATH")"

                for DT_NEEDED in $DT_NEEDED_LIST
                do
                    case $DT_NEEDED in
                        # besure DT_NEEDED entries all are filenames, not filepaths
                        lib*.so)
                            ;;
                        *)  abort 1 "unexpected so file: $LIBRARY_FILEPATH\n    invalid DT_NEEDED: $DT_NEEDED"
                    esac
                done

                if "$ANDROID_NDK_READELF" -d "$LIBRARY_FILEPATH" | grep -q 'libc++_shared\.so' ; then
                    STL=c++_shared
                elif "$ANDROID_NDK_NM" -D "$LIBRARY_FILEPATH" | grep -q 'T __cxa_' ; then
                    # https://softwareengineering.stackexchange.com/questions/262195/whats-wrong-with-statically-linking-the-stl-into-multiple-shared-libraries
                    # https://developer.android.com/ndk/guides/cpp-support
                    abort 1 "libc++_static.a has been linked into $LIBRARY_FILEPATH, this may case problems. For more details, please refer to https://developer.android.com/ndk/guides/cpp-support"
                fi
            fi

            printf "{\"ndk\": %s, \"api\": %s, \"abi\": \"%s\", \"stl\": \"%s\", \"static\": %s}" "${RECEIPT_PACKAGE_NDKVERS%%.*}" "$TARGET_PLATFORM_VERS" "$TARGET_PLATFORM_ABI" "$STL" "$IS_STATIC_LIBRARY" > "$ABI_DIR/abi.json"

        done
    done

    #########################################################################################

    step "packing the prefab aar file"
    run zip -9 -r prefab.aar .

    step "show size of the prefab aar file"
    run du -sh prefab.aar

    ###########################################################################################

    if [ "$NDKPKG_ARG1" = deploy ] ; then
        return 0
    fi

    if [ -z "$OUTPUT_PATH" ] ; then
        printf '%b\n' "
${COLOR_RED}NOT proceed due to -o <OUTPUT-PATH> option is unspecified.${COLOR_OFF}

${COLOR_RED}If you want to continue, please manually execute following commands:${COLOR_OFF}

cd $SESSION_DIR
mv prefab.aar /somewhere
cd -
rm -rf $SESSION_DIR\n"
        return 0
    fi

    ###########################################################################################

    OUTPUT_DIR="$(dirname "$OUTPUT_PATH")"

    if [ ! -d "$OUTPUT_DIR" ] ; then
        step "create the output directory"
        run install -d "$OUTPUT_DIR"
    fi

    ###########################################################################################

    step "rename prefab aar"
    DEFAULT_OUTPUT_FILENAME="$PREFAB_PACKAGE_NAME-$RECEIPT_PACKAGE_VERSION-android-$TARGET_PLATFORM_VERS-$(printf '%s\n' "$TARGET_PLATFORM_ABIS" | tr ' ' '+').aar"
    run mv prefab.aar "$DEFAULT_OUTPUT_FILENAME"

    ###########################################################################################

    step "back to origin directory"
    run cd -

    ###########################################################################################

    step "move prefab aar file to destination"
    run mv "$SESSION_DIR/$DEFAULT_OUTPUT_FILENAME" "$OUTPUT_PATH"

    if [ "$REQUEST_TO_KEEP_SESSION_DIR" = 1 ] ; then
        echo
        note "the session directory '$SESSION_DIR' is not deleted as -K option is specified."
    else
        step "delete the session directory"
        run rm -rf "$SESSION_DIR"
    fi
}

# __deploy_google_prefab_aar_for_the_given_installed_packages android-<ANDROID-API>/<ANDROID-ABIs>/<PACKAGE-NAME> [--ndk-home=<ANDROID-NDK-HOME>] [--groupId] [-K] [--dry-run] [--debug] [--remote < REMOTE-CONFIG-FILE]
  __deploy_google_prefab_aar_for_the_given_installed_packages() {
    __export_google_prefab_aar_for_the_given_installed_packages "$@"

    #########################################################################################

    shift

    unset DEPLOYED_TO_SONATYPE_OSSRH
    unset DEPLOYED_TO_LOCAL_PATH

    unset MVN_ARGS

    unset DRYRUN

    unset GROUPID

    while [ -n "$1" ]
    do
        case $1 in
            --ndk-home=*)
                ;;
            --debug)
                MVN_ARGS=-X
                ;;
            --remote)
                DEPLOYED_TO_SONATYPE_OSSRH=1
                ;;
            --local=*)
                DEPLOYED_TO_LOCAL_PATH="${1#*=}"
                if [ -n "$DEPLOYED_TO_LOCAL_PATH" ] ; then
                    cd -
                    DEPLOYED_TO_LOCAL_PATH="$(realpath -s "$DEPLOYED_TO_LOCAL_PATH")"
                    cd -
                fi
                ;;
            --dry-run)
                DRYRUN=1
                ;;
            -K) ;;
            -o) shift ;;
            --groupId=*)
                GROUPID="${1#*=}"
                ;;
            *)  abort 1 "unrecognized argument: $1"
        esac

        shift
    done

    #########################################################################################

    # https://central.sonatype.org/publish/release/
    # https://central.sonatype.org/publish/requirements/
    # https://central.sonatype.org/publish/publish-manual/

    if [ "$DEPLOYED_TO_SONATYPE_OSSRH" = 1 ] ; then
        if [ -z "$RECEIPT_PACKAGE_LICENSE" ] ; then
            abort 1 "can not be deployed to Sonatype OSSRH due to RECEIPT_PACKAGE_LICENSE is empty."
        fi

        if [ -z "$RECEIPT_PACKAGE_GIT_URL" ] ; then
            abort 1 "can not be deployed to Sonatype OSSRH due to RECEIPT_PACKAGE_GIT_URL is empty."
        fi

        if [ -n "$DEPLOYED_TO_LOCAL_PATH" ] ; then
            abort 1 '--remote and --local=<DIR> can not be used as the same time.'
        fi
    fi

    #########################################################################################

    [ -z "$GROUPID" ] && GROUPID="com.fpliu.ndk.pkg.prefab.android.$TARGET_PLATFORM_VERS"

    #########################################################################################

    step "generating POM file"

    cat > pom.xml <<EOF
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>$GROUPID</groupId>
    <artifactId>$PREFAB_PACKAGE_NAME</artifactId>
    <version>$RECEIPT_PACKAGE_VERSION</version>
    <packaging>aar</packaging>

    <name>$PREFAB_PACKAGE_NAME</name>
    <description>$RECEIPT_PACKAGE_SUMMARY</description>
    <url>$RECEIPT_PACKAGE_WEB_URL</url>
EOF

    RECEIPT_PACKAGE_SCM_URL=

    if [ -n "$RECEIPT_PACKAGE_GIT_URL" ] ; then
        RECEIPT_PACKAGE_SCM_TYPE=git
        RECEIPT_PACKAGE_SCM_URL="$RECEIPT_PACKAGE_GIT_URL"
    fi

    if [ -n "$RECEIPT_PACKAGE_SCM_URL" ] ; then
        cat >> pom.xml <<EOF

    <scm>
        <connection>scm:$RECEIPT_PACKAGE_SCM_TYPE:$RECEIPT_PACKAGE_SCM_URL</connection>
        <developerConnection>scm:$RECEIPT_PACKAGE_SCM_TYPE:$RECEIPT_PACKAGE_SCM_URL</developerConnection>
        <url>$RECEIPT_PACKAGE_SCM_URL</url>
    </scm>
EOF
    fi

    if [ -z "$RECEIPT_PACKAGE_DEVELOPER" ] ; then
        RECEIPT_PACKAGE_DEVELOPER="$PREFAB_PACKAGE_NAME developers <unknown>"
    fi

    printf '\n    <developers>\n' >> pom.xml

    export IFS='
'

    for DEVELOPER in $RECEIPT_PACKAGE_DEVELOPER
    do
        DEVELOPER_NAME=
        DEVELOPER_EMAIL=

        DEVELOPER_NAME="${DEVELOPER% <*>}"

        if [ "$DEVELOPER" != "$DEVELOPER_NAME" ] ; then
            DEVELOPER_EMAIL="$(printf '%s\n' "$DEVELOPER" | sed -e 's|.* <\(.*\)>|\1|')"
        fi

        cat >> pom.xml <<EOF
        <developer>
            <name>$DEVELOPER_NAME</name>
            <email>$DEVELOPER_EMAIL</email>
        </developer>
EOF
    done

    unset IFS

    printf '    </developers>\n' >> pom.xml

    if [ -n "$RECEIPT_PACKAGE_LICENSE" ] ; then
        printf '\n    <licenses>\n' >> pom.xml

        for LICENSE_NAME in $RECEIPT_PACKAGE_LICENSE
        do
            cat >> pom.xml <<EOF
        <license>
            <name>$LICENSE_NAME</name>
            <url>https://raw.githubusercontent.com/spdx/license-list-data/master/text/$LICENSE_NAME.txt</url>
        </license>
EOF
        done

        printf '    </licenses>\n' >> pom.xml
    fi

    printf '</project>\n' >> pom.xml

    cat pom.xml

    #########################################################################################

    POM_FILE="$PREFAB_PACKAGE_NAME-$RECEIPT_PACKAGE_VERSION.pom"

    # here we must rename pom.xml to another file name, otherwise it will be treated as a maven project.
    mv pom.xml "$POM_FILE"

    #########################################################################################

    if [ "$DEPLOYED_TO_SONATYPE_OSSRH" = 1 ] ; then
        unset SERVER_ID
        unset SERVER_URL
        unset SERVER_USERNAME
        unset SERVER_PASSWORD
        unset GPG_PASSPHRASE

        step "read config from stdin"
        while read -r LINE
        do
            case $LINE in
                SERVER_ID=*)        SERVER_ID="${LINE#*=}" ;;
                SERVER_URL=*)       SERVER_URL="${LINE#*=}" ;;
                SERVER_USERNAME=*)  SERVER_USERNAME="${LINE#*=}" ;;
                SERVER_PASSWORD=*)  SERVER_PASSWORD="${LINE#*=}" ;;
                GPG_PASSPHRASE=*)   GPG_PASSPHRASE="${LINE#*=}" ;;
            esac
        done

        [ -z "$SERVER_ID" ]       && abort 1 "SERVER_ID must not be enpty."
        [ -z "$SERVER_URL" ]      && abort 1 "SERVER_URL must not be enpty."
        [ -z "$SERVER_USERNAME" ] && abort 1 "SERVER_USERNAME must not be enpty."
        [ -z "$SERVER_PASSWORD" ] && abort 1 "SERVER_PASSWORD must not be enpty."
        [ -z "$GPG_PASSPHRASE"  ] && abort 1 "GPG_PASSPHRASE must not be enpty."

        #########################################################################################

        on_exit_deploy() {
            rm -f settings.xml
        }

        trap on_exit_deploy EXIT

        # https://maven.apache.org/plugins/maven-gpg-plugin/usage.html
        step "generating settings.xml"
        cat > settings.xml <<EOF
<?xml version="1.0" encoding="UTF-8"?>
<settings xmlns="http://maven.apache.org/SETTINGS/1.0.0"
          xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
          xsi:schemaLocation="http://maven.apache.org/SETTINGS/1.0.0 http://maven.apache.org/xsd/settings-1.0.0.xsd">
  <servers>
    <server>
      <id>$SERVER_ID</id>
      <username>$SERVER_USERNAME</username>
      <password>$SERVER_PASSWORD</password>
    </server>

    <server>
      <id>gpg.passphrase</id>
      <passphrase>$GPG_PASSPHRASE</passphrase>
    </server>
  </servers>
</settings>
EOF

        #########################################################################################

        # There are two maven plugins maven-deploy-plugin and maven-gpg-plugin can be used
        # maven-gpg-plugin is preferred as it is automatically signed with gpg.
        #
        # https://maven.apache.org/plugins/maven-gpg-plugin/sign-and-deploy-file-mojo.html
        # https://maven.apache.org/plugins/maven-deploy-plugin/deploy-file-mojo.html
        # https://maven.apache.org/resolver/configuration.html

        MVN_ARGS="$MVN_ARGS --settings settings.xml gpg:sign-and-deploy-file -Dfile=prefab.aar -DgeneratePom=false -DpomFile=$POM_FILE -Daether.checksums.algorithms=MD5,SHA-1,SHA-256,SHA-512 -DrepositoryId=$SERVER_ID -Durl=$SERVER_URL"
    else
        # https://maven.apache.org/plugins/maven-install-plugin/install-file-mojo.html
        MVN_ARGS="$MVN_ARGS install:install-file -Dfile=prefab.aar -DgroupId=$GROUPID -DartifactId=$PREFAB_PACKAGE_NAME -Dversion=$RECEIPT_PACKAGE_VERSION -Dpackaging=aar -DgeneratePom=false -DpomFile=$POM_FILE"

        if [ -n "$DEPLOYED_TO_LOCAL_PATH" ] ; then
            MVN_ARGS="$MVN_ARGS -DlocalRepositoryPath=$DEPLOYED_TO_LOCAL_PATH"
        fi
    fi

    #########################################################################################

    if [ "$DRYRUN" = 1 ] ; then
        printf '%b\n' "
${COLOR_RED}NOT proceed due to --dry-run option is specified.${COLOR_OFF}

${COLOR_RED}If you want to continue, please manually execute following commands:${COLOR_OFF}

cd $SESSION_DIR
run mvn $MVN_ARGS
cd -
rm -rf $SESSION_DIR\n"
        return 0
    fi

    #########################################################################################

    MVN="$(command -v mvn)" || {
        step install maven
        uppm install maven
        MVN="$UPPM_HOME/installed/maven/bin/mvn"
    }

    #########################################################################################

    step "deploying"
    run "$MVN $MVN_ARGS"

    #########################################################################################

    PREFAB_MODULES="$(find prefab/modules -maxdepth 1 -mindepth 1 -type d -printf '%f ')"

    #########################################################################################

    if [ "$REQUEST_TO_KEEP_SESSION_DIR" = 1 ] ; then
        printf '\n'
        note "the session directory '$SESSION_DIR' is not deleted as -K option is given."
    else
        step "delete the session directory"
        run rm -rf "$SESSION_DIR"
    fi

    #########################################################################################

    if [ "$DEPLOYED_TO_SONATYPE_OSSRH" = 1 ] ; then
        MAVEN_REPO_FUNC=mavenCentral
    else
        MAVEN_REPO_FUNC=mavenLocal
    fi

    #########################################################################################

    printf '%b\n' "
${COLOR_YELLOW}
======================================================
Use this artifact alongside with Android Gradle Plugin
======================================================${COLOR_OFF}

${COLOR_GREEN}step1. enable prefab feature for Android Gradle Plugin${COLOR_OFF}

android {
    buildFeatures {
        prefab true
    }
}

${COLOR_GREEN}step2. enable $MAVEN_REPO_FUNC repository for Gradle${COLOR_OFF}

repositories {
    $MAVEN_REPO_FUNC()
}

${COLOR_GREEN}step3. configure dependencies${COLOR_OFF}

${COLOR_PURPLE}For Gradle Groovy DSL:${COLOR_OFF}

dependencies {
    implementation '$GROUPID:$PREFAB_PACKAGE_NAME:$RECEIPT_PACKAGE_VERSION@aar'
}

${COLOR_PURPLE}For Gradle Kotlin DSL:${COLOR_OFF}

dependencies {
    implementation(\"$GROUPID:$PREFAB_PACKAGE_NAME:$RECEIPT_PACKAGE_VERSION@aar\")
}

${COLOR_GREEN}step4. find package and link libraries in your Android project's CMakeLists.txt${COLOR_OFF}

${COLOR_PURPLE}This prefab package has $(list_size $PREFAB_MODULES) modules : $PREFAB_MODULES${COLOR_OFF}

find_package($PREFAB_PACKAGE_NAME REQUIRED CONFIG)
target_link_libraries(app $PREFAB_PACKAGE_NAME::${PREFAB_MODULES%% *})

${COLOR_GREEN}step5. configure C++ standard and STL (optional)${COLOR_OFF}

android {
    defaultConfig {
        externalNativeBuild {
            cmake {
                arguments '-DANDROID_STL=c++_shared'
                cppFlags  '-std=c++17'
            }
        }
    }
}

${COLOR_RED}Caveat: If you link a shared library that depends on libc++_shared.so, then your Android app should use libc++_shared.so too.${COLOR_OFF}\n"
}

# }}}
##############################################################################
# {{{ ndk-pkg cleanup

__cleanup() {
    success "Done."
}

# }}}
##############################################################################
# {{{ ndk-pkg upgrade-self

# __upgrade_self <URL>
  __upgrade_self() {
    [ -z "$1" ] && abort 1 "__upgrade_self <URL> , <URL> must be non-empty."

    unset CURRENT_SCRIPT_REALPATH

    # if file exists and is a symbolic link
    if [ -L "$NDKPKG_PATH" ] ; then
        # https://unix.stackexchange.com/questions/136494/whats-the-difference-between-realpath-and-readlink-f#:~:text=GNU%20coreutils%20introduced%20a%20realpath,in%20common%20with%20GNU%20readlink%20.
        if command -v realpath > /dev/null ; then
            CURRENT_SCRIPT_REALPATH=$(realpath "$NDKPKG_PATH")
        elif command -v readlink > /dev/null && readlink -f xx > /dev/null 2>&1 ; then
            CURRENT_SCRIPT_REALPATH=$(readlink -f "$NDKPKG_PATH")
        else
            CURRENT_SCRIPT_REALPATH=$(realpath "$NDKPKG_PATH")
        fi
    else
        CURRENT_SCRIPT_REALPATH="$NDKPKG_PATH"
    fi

    SESSION_DIR="$NDKPKG_HOME/run/$$"

    run rm -rf     "$SESSION_DIR"
    run install -d "$SESSION_DIR"
    run cd         "$SESSION_DIR"

    wfetch "$1" -o self --no-buffer

    run chmod 755 self

    if [ -w "$CURRENT_SCRIPT_REALPATH" ] ; then
        run      mv self "$CURRENT_SCRIPT_REALPATH"
    else
        run sudo mv self "$CURRENT_SCRIPT_REALPATH"
    fi

    run rm -rf "$SESSION_DIR"
}

# }}}
##############################################################################
# {{{ ndk-pkg integrate zsh

# __integrate_zsh_completions <URL> [--output-dir=<DIR>]
  __integrate_zsh_completions() {
    [ -z "$1" ] && abort 1 "__integrate_zsh_completions <URL> [--output-dir=<DIR>] , <URL> must be non-empty."

    ZSH_COMPLETIONS_SCRIPT_URL="$1"

    shift

    unset OUTPUT_DIR

    for arg in "$@"
    do
        case $arg in
            --output-dir=*)
                OUTPUT_DIR="${1#*=}"

                case $OUTPUT_DIR in
                    '')   abort 1 "__integrate_zsh_completions <URL> [--output-dir=<DIR>] , <DIR> must be a non-empty string." ;;
                    \~)   OUTPUT_DIR="$HOME" ;;
                    \~/)  OUTPUT_DIR="$HOME" ;;
                    \~/.) OUTPUT_DIR="$HOME" ;;
                    \~/*) OUTPUT_DIR="$HOME/$(printf '%s\n' "$1" | cut -c3-)" ;;
                esac

                ;;
            *)  abort 1 "__integrate_zsh_completions <URL> [--output-dir=<DIR>] , unrecognized argument: $arg"
        esac
    done

    ZSH_COMPLETIONS_SCRIPT_FILENAME="_$(basename "$NDKPKG_ARG0")"

    if [ -n "$OUTPUT_DIR" ] ; then
        ZSH_COMPLETIONS_SCRIPT_OUT_FILEPATH="$OUTPUT_DIR/$ZSH_COMPLETIONS_SCRIPT_FILENAME"
    elif [ "$(uname)" = Linux ] && command -v termux-info > /dev/null && [ "$HOME" = '/data/data/com.termux/files/home' ] ; then
        ZSH_COMPLETIONS_SCRIPT_OUT_FILEPATH="/data/data/com.termux/files/usr/share/zsh/site-functions/$ZSH_COMPLETIONS_SCRIPT_FILENAME"
    else
        ZSH_COMPLETIONS_SCRIPT_OUT_FILEPATH="/usr/local/share/zsh/site-functions/$ZSH_COMPLETIONS_SCRIPT_FILENAME"
    fi

    # if file exists and is a symbolic link
    if [ -L "$ZSH_COMPLETIONS_SCRIPT_OUT_FILEPATH" ] ; then
        # https://unix.stackexchange.com/questions/136494/whats-the-difference-between-realpath-and-readlink-f#:~:text=GNU%20coreutils%20introduced%20a%20realpath,in%20common%20with%20GNU%20readlink%20.
        if command -v realpath > /dev/null ; then
            ZSH_COMPLETIONS_SCRIPT_OUT_FILEPATH=$(realpath "$ZSH_COMPLETIONS_SCRIPT_OUT_FILEPATH")
        elif command -v readlink > /dev/null && readlink -f xx > /dev/null 2>&1 ; then
            ZSH_COMPLETIONS_SCRIPT_OUT_FILEPATH=$(readlink -f "$ZSH_COMPLETIONS_SCRIPT_OUT_FILEPATH")
        else
            ZSH_COMPLETIONS_SCRIPT_OUT_FILEPATH=$(realpath "$ZSH_COMPLETIONS_SCRIPT_OUT_FILEPATH")
        fi
    fi

    SESSION_DIR="$NDKPKG_HOME/run/$$"

    run rm -rf     "$SESSION_DIR"
    run install -d "$SESSION_DIR"
    run cd         "$SESSION_DIR"

    wfetch "$ZSH_COMPLETIONS_SCRIPT_URL" -o _ndk-pkg --no-buffer

    run chmod 644 _ndk-pkg

    if [ -f "$ZSH_COMPLETIONS_SCRIPT_OUT_FILEPATH" ] ; then
        if [ -w "$ZSH_COMPLETIONS_SCRIPT_OUT_FILEPATH" ] ; then
            run      mv _ndk-pkg "$ZSH_COMPLETIONS_SCRIPT_OUT_FILEPATH"
        else
            run sudo mv _ndk-pkg "$ZSH_COMPLETIONS_SCRIPT_OUT_FILEPATH"
        fi
    else
        ZSH_COMPLETIONS_SCRIPT_OUT_DIR="$(dirname "$ZSH_COMPLETIONS_SCRIPT_OUT_FILEPATH")"

        if [ ! -d "$ZSH_COMPLETIONS_SCRIPT_OUT_DIR" ] ; then
            run install -d "$ZSH_COMPLETIONS_SCRIPT_OUT_DIR" || run sudo install -d "$ZSH_COMPLETIONS_SCRIPT_OUT_DIR"
        fi

        if [ -w "$ZSH_COMPLETIONS_SCRIPT_OUT_DIR" ] ; then
            run      mv _ndk-pkg "$ZSH_COMPLETIONS_SCRIPT_OUT_FILEPATH"
        else
            run sudo mv _ndk-pkg "$ZSH_COMPLETIONS_SCRIPT_OUT_FILEPATH"
        fi
    fi

    run rm -rf "$SESSION_DIR"

    printf '\n'
    note "${COLOR_YELLOW}you may need to run command${COLOR_RED} ${COLOR_GREEN}autoload -U compinit && compinit${COLOR_OFF} ${COLOR_YELLOW}in zsh to make it work.${COLOR_OFF}"
}

# }}}
##############################################################################
# {{{ ndk-pkg gen-url-transform-sample

__gen_url_transform_sample() {
    SESSION_DIR="$NDKPKG_HOME/run/$$"

    rm -rf     "$SESSION_DIR"
    install -d "$SESSION_DIR"
    cd         "$SESSION_DIR"

    cat > url-transform.sample <<EOF
#!/bin/sh

case \$1 in
    *githubusercontent.com/*)
        printf 'https://ghfast.top/%s\n' "\$1"
        ;;
    https://github.com/*)
        printf 'https://ghfast.top/%s\n' "\$1"
        ;;
    '') printf '%s\n' "\$0 <URL>, <URL> is unspecified." >&2 ; exit 1 ;;
    *)  printf '%s\n' "\$1"
esac
EOF

    chmod +x url-transform.sample

    install -d "$NDKPKG_HOME"

    mv url-transform.sample "$NDKPKG_HOME/"

    rm -rf "$SESSION_DIR"

    success "url-transform sample has been written into $NDKPKG_HOME/url-transform.sample"
    note "You can rename url-transform.sample to url-transform then edit it to meet your needs. To apply this, you should run 'export NDKPKG_URL_TRANSFORM=$NDKPKG_HOME/url-transform' in your terminal."
}

# }}}
##############################################################################
# {{{ ndk-pkg depends

# __show_packages_depended_by_the_given_package <PACKAGE-NAME> [-t <d2|dot|box|svg|png>] [-o <OUTPUT-PATH>] [--engine=<d2|dot>]
__show_packages_depended_by_the_given_package() {
    [ -z "$1" ] && abort 1 "$NDKPKG_ARG0 depends <PACKAGE-NAME> [-t <OUTPUT-TYPE>] [-o <OUTPUT-PATH>], <PACKAGE-NAME> is unspecified."

    PACKAGE_NAME="$1"

    shift

    ###########################################################################################

    unset OUTPUT_TYPE
    unset OUTPUT_PATH

    unset ENGINE

    while [ -n "$1" ]
    do
        case $1 in
            -t) shift
                case $1 in
                    d2|dot|box|svg|png)
                        OUTPUT_TYPE="$1" ;;
                    '') abort 1 "$NDKPKG_ARG0 depends <PACKAGE-NAME> [-t <OUTPUT-TYPE>] [-o <OUTPUT-PATH>], -t option is given but <OUTPUT-TYPE> is unspecified." ;;
                    *)  abort 1 "$NDKPKG_ARG0 depends <PACKAGE-NAME> [-t <OUTPUT-TYPE>], unsupported <OUTPUT-TYPE>: $1, <OUTPUT-TYPE> should be one of dot|d2|box|svg|png"
                esac
                ;;
            -o) shift
                if [ -z "$1" ] ; then
                    abort 1 "$NDKPKG_ARG0 depends <PACKAGE-NAME> [-t <OUTPUT-TYPE>] [-o <OUTPUT-PATH>], -o option is given but <OUTPUT-PATH> is unspecified."
                else
                    OUTPUT_PATH="$1"
                fi
                ;;
            --engine=*)
                ENGINE="${1#*=}"
                case $ENGINE in
                    d2|dot) ;;
                    *)  abort 1 "unrecognized diagram engine '$ENGINE', ndk-pkg only support d2 and dot diagram engine."
                esac
                ;;
            *)  abort 1 "$NDKPKG_ARG0 depends <PACKAGE-NAME> [-t <OUTPUT-TYPE>] [-o <OUTPUT-PATH>] [-K], unrecognized option: $1"
        esac
        shift
    done

    ###########################################################################################

    unset OUTPUT_DIR
    unset OUTPUT_FILEPATH

    case $OUTPUT_PATH in
        '')
            if [ -z "$OUTPUT_TYPE" ] ; then
                OUTPUT_TYPE='box'
            fi
            ;;
        ..|../)
            if [ -z "$OUTPUT_TYPE" ] ; then
                OUTPUT_TYPE='box'
            fi

            OUTPUT_FILEPATH="$PWD/../$PACKAGE_NAME-dependencies.$OUTPUT_TYPE"
            ;;
        .|./)
            if [ -z "$OUTPUT_TYPE" ] ; then
                OUTPUT_TYPE='box'
            fi

            OUTPUT_FILEPATH="$PWD/$PACKAGE_NAME-dependencies.$OUTPUT_TYPE"
            ;;
        */)
            if [ -z "$OUTPUT_TYPE" ] ; then
                OUTPUT_TYPE='box'
            fi

            case $OUTPUT_PATH in
                /*) OUTPUT_DIR="$OUTPUT_PATH" ;;
                *)  OUTPUT_DIR="$PWD/$OUTPUT_PATH"
            esac

            OUTPUT_FILEPATH="$OUTPUT_DIR/$PACKAGE_NAME-dependencies.$OUTPUT_TYPE"
            ;;
        *)
            if [ -z "$OUTPUT_TYPE" ] ; then
                case $OUTPUT_PATH in
                    *.box) OUTPUT_TYPE='box' ;;
                    *.dot) OUTPUT_TYPE='dot' ;;
                    *.d2)  OUTPUT_TYPE='d2'  ;;
                    *.svg) OUTPUT_TYPE='svg' ;;
                    *.png) OUTPUT_TYPE='png' ;;
                    *)     OUTPUT_TYPE='box' ;;
                esac
            fi

            case $OUTPUT_PATH in
                /*) OUTPUT_DIR="${OUTPUT_PATH%/*}"
                    OUTPUT_FILEPATH="$OUTPUT_PATH"
                    ;;
                *)  OUTPUT_DIR="$PWD/$(dirname "$OUTPUT_PATH")"
                    OUTPUT_FILEPATH="$PWD/$OUTPUT_PATH"
            esac
    esac

    ###########################################################################################

    if [ -z "$ENGINE" ] ; then
        if [ "$OUTPUT_TYPE" = svg ] || [ "$OUTPUT_TYPE" = png ] ; then
            if command -v dot > /dev/null ; then
                ENGINE=dot
            elif command -v dot_static > /dev/null ; then
                ENGINE=dot_static
            elif command -v d2 > /dev/null ; then
                ENGINE=d2
            else
                abort 1 'none of dot, dot_static, d2 command was found. please install graphviz or d2 package, then try again.'
            fi
        fi
    else
        if [ "$ENGINE" = dot ] ; then
            ENGINE=dot_static
        fi
    fi

    ###########################################################################################

    unset GENERATE_D2

    if [ "$OUTPUT_TYPE" = d2 ] || [ "$ENGINE" = d2 ] ; then
        GENERATE_D2=1
    fi

    ###########################################################################################

    unset LINES

    unset HANDLED_PACKAGE_NAME_LIST

    unset STACK

    STACK="$PACKAGE_NAME"

    while [ -n "$STACK" ]
    do
        case $STACK in
            *\;*) PACKAGE_NAME="${STACK##*;}" ; STACK="${STACK%;*}" ;;
            *)    PACKAGE_NAME="${STACK}"     ; STACK=
        esac

        ################################################################

        HANDLED=0

        for HANDLED_PACKAGE_NAME in $HANDLED_PACKAGE_NAME_LIST
        do
            if [ "$HANDLED_PACKAGE_NAME" = "$PACKAGE_NAME" ] ; then
                HANDLED=1
                break
            fi
        done

        if [ "$HANDLED" = 1 ] ; then
            continue
        else
            HANDLED_PACKAGE_NAME_LIST="$HANDLED_PACKAGE_NAME_LIST $PACKAGE_NAME"
        fi

        #echo "HANDLED_PACKAGE_NAME_LIST=$HANDLED_PACKAGE_NAME_LIST"

        ################################################################

        __load_formula_of_the_given_package "$PACKAGE_NAME"

        ################################################################

        [ -z "$PACKAGE_DEP_PKG" ] && continue

        ################################################################

        if [ "$GENERATE_D2" = 1 ] ; then
            for item in $PACKAGE_DEP_PKG
            do
                LINES="$LINES
$PACKAGE_NAME -> $item"
            done
        else
            DOUBLE_QUOTE_LIST=

            for item in $PACKAGE_DEP_PKG
            do
                DOUBLE_QUOTE_LIST="$DOUBLE_QUOTE_LIST \"$item\""
            done

            LINES="$LINES
\"$PACKAGE_NAME\" -> {$DOUBLE_QUOTE_LIST }"
        fi

        ################################################################

        for DEPENDENT_PACKAGE_NAME in $PACKAGE_DEP_PKG
        do
            if [ "$DEPENDENT_PACKAGE_NAME" = "$PACKAGE_NAME" ] ; then
                abort 1 "package '$PACKAGE_NAME' depends itself."
            fi

            if [ -z "$STACK" ] ; then
                STACK="$DEPENDENT_PACKAGE_NAME"
            else
                STACK="$STACK;$DEPENDENT_PACKAGE_NAME"
            fi
        done
    done

    ###########################################################################################

    [ -z "$LINES" ] && return 0

    ###########################################################################################

    case $OUTPUT_TYPE in
        dot)
            if [ -z "$OUTPUT_FILEPATH" ] ; then
                printf 'digraph G {\n%s\n}\n' "$LINES"
            else
                SESSION_DIR="$NDKPKG_HOME/run/$$"

                rm -rf     "$SESSION_DIR"
                install -d "$SESSION_DIR"
                cd         "$SESSION_DIR"

                printf 'digraph G {\n%s\n}\n' "$LINES" > dependencies.dot

                if [ -n "$OUTPUT_DIR" ] && [ ! -d "$OUTPUT_DIR" ] ; then
                    install -d "$OUTPUT_DIR"
                fi

                mv -T dependencies.dot "$OUTPUT_FILEPATH"

                rm -rf "$SESSION_DIR"
            fi
            ;;
        d2)
            if [ -z "$OUTPUT_FILEPATH" ] ; then
                printf '%s\n' "$LINES"
            else
                SESSION_DIR="$NDKPKG_HOME/run/$$"

                rm -rf     "$SESSION_DIR"
                install -d "$SESSION_DIR"
                cd         "$SESSION_DIR"

                printf '%s\n' "$LINES" > dependencies.d2

                if [ -n "$OUTPUT_DIR" ] && [ ! -d "$OUTPUT_DIR" ] ; then
                    install -d "$OUTPUT_DIR"
                fi

                mv -T dependencies.d2 "$OUTPUT_FILEPATH"

                rm -rf "$SESSION_DIR"
            fi
            ;;
        box)
            DOT_CONTENT="digraph G {
$LINES
}"

            if [ -z "$OUTPUT_FILEPATH" ] ; then
                # https://github.com/ggerganov/dot-to-ascii
                curl \
                    -s \
                    -G \
                    --data-urlencode "boxart=1" \
                    --data-urlencode "src=$DOT_CONTENT" \
                    'https://dot-to-ascii.ggerganov.com/dot-to-ascii.php'
            else
                SESSION_DIR="$NDKPKG_HOME/run/$$"

                rm -rf     "$SESSION_DIR"
                install -d "$SESSION_DIR"
                cd         "$SESSION_DIR"

                # https://github.com/ggerganov/dot-to-ascii
                curl \
                    -s \
                    -G \
                    -o dependencies.box \
                    --data-urlencode "boxart=1" \
                    --data-urlencode "src=$DOT_CONTENT" \
                    'https://dot-to-ascii.ggerganov.com/dot-to-ascii.php'

                if [ -n "$OUTPUT_DIR" ] && [ ! -d "$OUTPUT_DIR" ] ; then
                    install -d "$OUTPUT_DIR"
                fi

                mv dependencies.box "$OUTPUT_FILEPATH"

                rm -rf "$SESSION_DIR"
            fi
            ;;
        svg|png)
            if [ "$ENGINE" = d2 ] ; then
                if [ -z "$OUTPUT_FILEPATH" ] ; then
                    printf '%s\n' "$LINES" | d2 -
                else
                    if [ -n "$OUTPUT_DIR" ] && [ ! -d "$OUTPUT_DIR" ] ; then
                        install -d "$OUTPUT_DIR"
                    fi

                    printf '%s\n' "$LINES" | d2 - "$OUTPUT_FILEPATH"
                fi
            else
                SESSION_DIR="$NDKPKG_HOME/run/$$"

                rm -rf     "$SESSION_DIR"
                install -d "$SESSION_DIR"
                cd         "$SESSION_DIR"

                printf 'digraph G {\n%s\n}\n' "$LINES" > dependencies.dot

                if [ -z "$OUTPUT_FILEPATH" ] ; then
                    "$ENGINE" "-T$OUTPUT_TYPE" dependencies.dot
                else
                    "$ENGINE" "-T$OUTPUT_TYPE" -o dependencies.tmp dependencies.dot

                    if [ -n "$OUTPUT_DIR" ] && [ ! -d "$OUTPUT_DIR" ] ; then
                        install -d "$OUTPUT_DIR"
                    fi

                    mv -T dependencies.tmp "$OUTPUT_FILEPATH"
                fi

                rm -rf "$SESSION_DIR"
            fi
    esac
}


# }}}
##############################################################################
# {{{ ndk-pkg uninstall

__uninstall_the_given_packages() {
    [ -z "$1" ] && abort 1 "neither package-name nor package-spec is specified."

    unset PACKAGE_SPECS

    for item in "$@"
    do
        PACKAGE_SPECS="$PACKAGE_SPECS $(inspect_package_spec "$item")"
    done

    for PACKAGE_SPEC in $PACKAGE_SPECS
    do
        PACKAGE_INSTALLED_LINK_DIR="$NDKPKG_PACKAGE_INSTALLED_ROOT/$PACKAGE_SPEC"

        [ -e "$PACKAGE_INSTALLED_LINK_DIR" ] || abort 10 "package '$PACKAGE_SPEC' is not installed."
        [ -L "$PACKAGE_INSTALLED_LINK_DIR" ] || abort 11 "$PACKAGE_INSTALLED_LINK_DIR was expected a symlink, but it was not."
        [ -d "$PACKAGE_INSTALLED_LINK_DIR" ] || abort 12 "$PACKAGE_INSTALLED_LINK_DIR was expected a symlink refer to a directory, but it was not."

        PACKAGE_INSTALLED_REAL_DIR="$(readlink -f "$PACKAGE_INSTALLED_LINK_DIR")"

        [ -d "$PACKAGE_INSTALLED_REAL_DIR" ] || abort 13 "directory $PACKAGE_INSTALLED_REAL_DIR was expected exists, but it was not."

        PACKAGE_MANIFEST_FILEPATH="$PACKAGE_INSTALLED_REAL_DIR/.ndk-pkg/MANIFEST.txt"

        [ -f "$PACKAGE_MANIFEST_FILEPATH" ] || abort 13 "$PACKAGE_MANIFEST_FILEPATH file was expected exist, but it was not."

        PACKAGE_RECEIPT_FILEPATH="$PACKAGE_INSTALLED_REAL_DIR/.ndk-pkg/RECEIPT.yml"

        [ -f "$PACKAGE_RECEIPT_FILEPATH" ] || abort 14 "$PACKAGE_RECEIPT_FILEPATH file was expected exist, but it was not."

        run rm -ff "$PACKAGE_INSTALLED_LINK_DIR"
        run rm -rf "$PACKAGE_INSTALLED_REAL_DIR"
    done
}

# }}}
##############################################################################
# {{{ ndk-pkg reinstall

__reinstall_the_given_packages() {
    inspect_install_arguments "$@"

    [ -z "$SPECIFIED_PACKAGE_SPEC_LIST" ] && abort 1 "neither package-name nor package-spec is specified."

    #########################################################################################

    SESSION_DIR="$NDKPKG_HOME/run/$$"

    rm -rf     "$SESSION_DIR"
    install -d "$SESSION_DIR"

    #########################################################################################

    # 1. check if has circle
    # 2. backup formulas
    # 3. cache variables

    for SPECIFIED_PACKAGE_SPEC in $SPECIFIED_PACKAGE_SPEC_LIST
    do
        PACKAGE_NAME_STACK="${SPECIFIED_PACKAGE_SPEC##*/}"

        while [ -n "$PACKAGE_NAME_STACK" ]
        do
            case $PACKAGE_NAME_STACK in
                *\;*) PACKAGE_NAME="${PACKAGE_NAME_STACK##*;}" ; PACKAGE_NAME_STACK="${PACKAGE_NAME_STACK%;*}" ;;
                *)    PACKAGE_NAME="${PACKAGE_NAME_STACK}"     ; PACKAGE_NAME_STACK=
            esac

            if [ -f "$SESSION_DIR/$PACKAGE_NAME.yml" ] ; then
                continue
            fi

            __load_formula_of_the_given_package "$PACKAGE_NAME"

            cp -L "$PACKAGE_FORMULA_FILEPATH" "$SESSION_DIR/$PACKAGE_NAME.yml"

            eval "PACKAGE_DEP_PKG_${PACKAGE_NAME_UPPERCASE_UNDERSCORE}='$PACKAGE_DEP_PKG'"

            for DEPENDENT_PACKAGE_NAME in $PACKAGE_DEP_PKG
            do
                if [ "$DEPENDENT_PACKAGE_NAME" = "$PACKAGE_NAME" ] ; then
                    abort 1 "package '$PACKAGE_NAME' depends itself."
                fi

                if [ -z "$PACKAGE_NAME_STACK" ] ; then
                    PACKAGE_NAME_STACK="$DEPENDENT_PACKAGE_NAME"
                else
                    PACKAGE_NAME_STACK="$PACKAGE_NAME_STACK;$DEPENDENT_PACKAGE_NAME"
                fi
            done
        done
    done

    #########################################################################################

    for SPECIFIED_PACKAGE_SPEC in $SPECIFIED_PACKAGE_SPEC_LIST
    do
        TARGET_PLATFORM_SPEC="${SPECIFIED_PACKAGE_SPEC%/*}"

        TARGET_PLATFORM_NAME=
        TARGET_PLATFORM_VERS=
        TARGET_PLATFORM_ARCH=

        TARGET_PLATFORM_NAME="$(printf '%s\n' "$TARGET_PLATFORM_SPEC" | cut -d- -f1)"
        TARGET_PLATFORM_VERS="$(printf '%s\n' "$TARGET_PLATFORM_SPEC" | cut -d- -f2)"
        TARGET_PLATFORM_ARCH="$(printf '%s\n' "$TARGET_PLATFORM_SPEC" | cut -c 12-)"

        ##################################################################

        REQUESTED_PACKAGE_NAME_LIST=

        PACKAGE_NAME_STACK="${SPECIFIED_PACKAGE_SPEC##*/}"

        while [ -n "$PACKAGE_NAME_STACK" ]
        do
            case $PACKAGE_NAME_STACK in
                *\;*) PACKAGE_NAME="${PACKAGE_NAME_STACK##*;}" ; PACKAGE_NAME_STACK="${PACKAGE_NAME_STACK%;*}" ;;
                *)    PACKAGE_NAME="${PACKAGE_NAME_STACK}"     ; PACKAGE_NAME_STACK=
            esac

            ##################################################################

            REQUESTED_PACKAGE_NAME_LIST2="$PACKAGE_NAME"

            for item in $REQUESTED_PACKAGE_NAME_LIST
            do
                [ "$item" = "$PACKAGE_NAME" ] && continue
                REQUESTED_PACKAGE_NAME_LIST2="$REQUESTED_PACKAGE_NAME_LIST2 $item"
            done

            REQUESTED_PACKAGE_NAME_LIST="$REQUESTED_PACKAGE_NAME_LIST2"

            ##################################################################

            PACKAGE_NAME_UPPERCASE_UNDERSCORE="$(printf '%s\n' "$PACKAGE_NAME" | tr a-z A-Z | tr '@+-.' '_')"

            for item in $(eval echo \$PACKAGE_DEP_PKG_"${PACKAGE_NAME_UPPERCASE_UNDERSCORE}")
            do
                if [ -z "$PACKAGE_NAME_STACK" ] ; then
                    PACKAGE_NAME_STACK="$item"
                else
                    PACKAGE_NAME_STACK="$PACKAGE_NAME_STACK;$item"
                fi
            done
        done

        ##################################################################

        for PACKAGE_NAME in $REQUESTED_PACKAGE_NAME_LIST
        do
            PACKAGE_SPEC="$TARGET_PLATFORM_SPEC/$PACKAGE_NAME"

            PACKAGE_INSTALLED_LINK_DIR="$NDKPKG_PACKAGE_INSTALLED_ROOT/$PACKAGE_SPEC"
            PACKAGE_INSTALLED_REAL_DIR="$(readlink -f "$PACKAGE_INSTALLED_LINK_DIR")"

            (__install_the_given_package "$PACKAGE_SPEC")

            rm -rf "$PACKAGE_INSTALLED_REAL_DIR"
        done
    done

    #########################################################################################

    if [ "$REQUEST_TO_KEEP_SESSION_DIR" != 1 ] ; then
        rm -rf "$SESSION_DIR"
    fi
}

# }}}
##############################################################################
# {{{ ndk-pkg upgrade

__upgrade_packages() {
    inspect_install_arguments "$@"

    if [ -z "$SPECIFIED_PACKAGE_SPEC_LIST" ] ; then
        SPECIFIED_PACKAGE_SPEC_LIST=$(__list__outdated_packages)
    fi

    if [ -z "$SPECIFIED_PACKAGE_SPEC_LIST" ] ; then
        return 0
    fi

    #########################################################################################

    SESSION_DIR="$NDKPKG_HOME/run/$$"

    rm -rf     "$SESSION_DIR"
    install -d "$SESSION_DIR"

    #########################################################################################

    # 1. check if has circle
    # 2. backup formulas
    # 3. cache variables

    for SPECIFIED_PACKAGE_SPEC in $SPECIFIED_PACKAGE_SPEC_LIST
    do
        PACKAGE_NAME_STACK="${SPECIFIED_PACKAGE_SPEC##*/}"

        while [ -n "$PACKAGE_NAME_STACK" ]
        do
            case $PACKAGE_NAME_STACK in
                *\;*) PACKAGE_NAME="${PACKAGE_NAME_STACK##*;}" ; PACKAGE_NAME_STACK="${PACKAGE_NAME_STACK%;*}" ;;
                *)    PACKAGE_NAME="${PACKAGE_NAME_STACK}"     ; PACKAGE_NAME_STACK=
            esac

            if [ -f "$SESSION_DIR/$PACKAGE_NAME.yml" ] ; then
                continue
            fi

            __load_formula_of_the_given_package "$PACKAGE_NAME"

            cp -L "$PACKAGE_FORMULA_FILEPATH" "$SESSION_DIR/$PACKAGE_NAME.yml"

            eval "PACKAGE_DEP_PKG_${PACKAGE_NAME_UPPERCASE_UNDERSCORE}='$PACKAGE_DEP_PKG'"

            for DEPENDENT_PACKAGE_NAME in $PACKAGE_DEP_PKG
            do
                if [ "$DEPENDENT_PACKAGE_NAME" = "$PACKAGE_NAME" ] ; then
                    abort 1 "package '$PACKAGE_NAME' depends itself."
                fi

                if [ -z "$PACKAGE_NAME_STACK" ] ; then
                    PACKAGE_NAME_STACK="$DEPENDENT_PACKAGE_NAME"
                else
                    PACKAGE_NAME_STACK="$PACKAGE_NAME_STACK;$DEPENDENT_PACKAGE_NAME"
                fi
            done
        done
    done

    #########################################################################################

    for SPECIFIED_PACKAGE_SPEC in $SPECIFIED_PACKAGE_SPEC_LIST
    do
        TARGET_PLATFORM_SPEC="${SPECIFIED_PACKAGE_SPEC%/*}"

        TARGET_PLATFORM_NAME=
        TARGET_PLATFORM_VERS=
        TARGET_PLATFORM_ARCH=

        TARGET_PLATFORM_NAME="$(printf '%s\n' "$TARGET_PLATFORM_SPEC" | cut -d- -f1)"
        TARGET_PLATFORM_VERS="$(printf '%s\n' "$TARGET_PLATFORM_SPEC" | cut -d- -f2)"
        TARGET_PLATFORM_ARCH="$(printf '%s\n' "$TARGET_PLATFORM_SPEC" | cut -c 12-)"

        ##################################################################

        REQUESTED_PACKAGE_NAME_LIST=

        PACKAGE_NAME_STACK="${SPECIFIED_PACKAGE_SPEC##*/}"

        while [ -n "$PACKAGE_NAME_STACK" ]
        do
            case $PACKAGE_NAME_STACK in
                *\;*) PACKAGE_NAME="${PACKAGE_NAME_STACK##*;}" ; PACKAGE_NAME_STACK="${PACKAGE_NAME_STACK%;*}" ;;
                *)    PACKAGE_NAME="${PACKAGE_NAME_STACK}"     ; PACKAGE_NAME_STACK=
            esac

            ##################################################################

            REQUESTED_PACKAGE_NAME_LIST2="$PACKAGE_NAME"

            for item in $REQUESTED_PACKAGE_NAME_LIST
            do
                [ "$item" = "$PACKAGE_NAME" ] && continue
                REQUESTED_PACKAGE_NAME_LIST2="$REQUESTED_PACKAGE_NAME_LIST2 $item"
            done

            REQUESTED_PACKAGE_NAME_LIST="$REQUESTED_PACKAGE_NAME_LIST2"

            ##################################################################

            PACKAGE_NAME_UPPERCASE_UNDERSCORE="$(printf '%s\n' "$PACKAGE_NAME" | tr a-z A-Z | tr '@+-.' '_')"

            for item in $(eval echo \$PACKAGE_DEP_PKG_"${PACKAGE_NAME_UPPERCASE_UNDERSCORE}")
            do
                if [ -z "$PACKAGE_NAME_STACK" ] ; then
                    PACKAGE_NAME_STACK="$item"
                else
                    PACKAGE_NAME_STACK="$PACKAGE_NAME_STACK;$item"
                fi
            done
        done

        ##################################################################

        for PACKAGE_NAME in $REQUESTED_PACKAGE_NAME_LIST
        do
            PACKAGE_SPEC="$TARGET_PLATFORM_SPEC/$PACKAGE_NAME"

            is_package__outdated "$PACKAGE_SPEC" || {
                note 1 "$PACKAGE_SPEC is not outdated."
                continue
            }

            PACKAGE_INSTALLED_LINK_DIR="$NDKPKG_PACKAGE_INSTALLED_ROOT/$PACKAGE_SPEC"
            PACKAGE_INSTALLED_REAL_DIR="$(readlink -f "$PACKAGE_INSTALLED_LINK_DIR")"

            (__install_the_given_package "$PACKAGE_SPEC")

            rm -rf "$PACKAGE_INSTALLED_REAL_DIR"
        done
    done

    #########################################################################################

    if [ "$REQUEST_TO_KEEP_SESSION_DIR" != 1 ] ; then
        rm -rf "$SESSION_DIR"
    fi
}

# }}}
##############################################################################
# {{{ ndk-pkg install

# inspect_package_spec <PACKAGE-NAME|PACKAGE-SPEC>
  inspect_package_spec() {
    case $1 in
        '') abort 1 "neither package-name nor package-spec is specified."
            ;;
        */*)
            case $1 in
                android-[1-9][0-9]-armeabi-v7a/*)
                    TARGET_PLATFORM_ABI='armeabi-v7a'
                    ;;
                android-[1-9][0-9]-arm64-v8a/*)
                    TARGET_PLATFORM_ABI='arm64-v8a'
                    ;;
                android-[1-9][0-9]-x86/*)
                    TARGET_PLATFORM_ABI='x86'
                    ;;
                android-[1-9][0-9]-x86_64/*)
                    TARGET_PLATFORM_ABI='x86_64'
                    ;;
                *)  abort 1 "invalid package spec: $1"
            esac 

            PACKAGE_NAME="${1##*/}"

            if [ -z "$PACKAGE_NAME" ] ; then
                abort 1 "invalid package spec: $1\n    package name is unspecifed."
            elif printf '%s\n' "$PACKAGE_NAME" | grep -q -E '^[A-Za-z0-9+-_.@]{1,50}$' ; then
                :
            else
                abort 1 "invalid package spec: $1\n    package name must match the regular expression pattern: ^[A-Za-z0-9+-_.@]{1,50}$"
            fi

            TARGET_PLATFORM_SPEC="${1%/*}"
            TARGET_PLATFORM_VERS="$(printf '%s\n' "$TARGET_PLATFORM_SPEC" | cut -d- -f2)"

            PACKAGE_SPEC="$1"
            ;;
        *)  if printf '%s\n' "$1" | grep -q -E '^[A-Za-z0-9+-_.@]{1,50}$' ; then
                case $NDKPKG_DEFAULT_TARGET in
                    '') NDKPKG_DEFAULT_TARGET='android-21-arm64-v8a'
                        ;;
                    android-[1-9][0-9]-armeabi-v7a)
                        ;;
                    android-[1-9][0-9]-arm64-v8a)
                        ;;
                    android-[1-9][0-9]-x86)
                        ;;
                    android-[1-9][0-9]-x86_64)
                        ;;
                    *) abort 1 "you have set NDKPKG_DEFAULT_TARGET=$NDKPKG_DEFAULT_TARGET , but it is an invalid target spec."
                esac

                PACKAGE_SPEC="$NDKPKG_DEFAULT_TARGET/$1"
            else
                abort 1 "invalid package name: $1"
            fi
    esac

    printf '%s\n' "$PACKAGE_SPEC"
}

# inspect_package_spec_list <PACKAGE-NAME | PACKAGE-SPECS> [USER-SPECIFIED-TARGET]
  inspect_package_spec_list() {
    case $1 in
        '') abort 1 "neither package-name nor package-specs is specified."
            ;;
        */*)
            PACKAGE_NAME="${1##*/}"

            if [ -z "$PACKAGE_NAME" ] ; then
                abort 1 "invalid package spec: $1\n    package name is unspecifed."
            elif printf '%s\n' "$PACKAGE_NAME" | grep -q -E '^[A-Za-z0-9+-_.@]{1,50}$' ; then
                :
            else
                abort 1 "invalid package spec: $1\n    package name must match the regular expression pattern: ^[A-Za-z0-9+-_.@]{1,50}$"
            fi

            TARGET_PLATFORM_SPEC="${1%/*}"

            case $TARGET_PLATFORM_SPEC in
                android-[1-9][0-9]-*) ;;
                *)  abort 1 "invalid package spec: $1"
            esac

            TARGET_PLATFORM_VERS="$(printf '%s\n' "$TARGET_PLATFORM_SPEC" | cut -d- -f2)"
            TARGET_PLATFORM_ABIS="$(printf '%s\n' "$TARGET_PLATFORM_SPEC" | cut -c 12- | tr ',' ' ')"

            unset PACKAGE_SPEC_LIST

            for TARGET_PLATFORM_ABI in $TARGET_PLATFORM_ABIS
            do
                case $TARGET_PLATFORM_ABI in
                    armeabi-v7a|arm64-v8a|x86|x86_64)
                        PACKAGE_SPEC_LIST="$PACKAGE_SPEC_LIST android-$TARGET_PLATFORM_VERS-$TARGET_PLATFORM_ABI/$PACKAGE_NAME"
                        ;;
                    *)  abort 1 "invalid package spec: $1\n    unrecognized android abi: $TARGET_PLATFORM_ABI"
                esac
            done

            printf '%s\n' "$PACKAGE_SPEC_LIST"
            ;;
        *)  if printf '%s\n' "$1" | grep -q -E '^[A-Za-z0-9+-_.@]{1,50}$' ; then
                if [ -z "$2" ] ; then
                    case $NDKPKG_DEFAULT_TARGET in
                        '') NDKPKG_DEFAULT_TARGET='android-21-arm64-v8a'
                            ;;
                        android-[1-9][0-9]-armeabi-v7a)
                            ;;
                        android-[1-9][0-9]-arm64-v8a)
                            ;;
                        android-[1-9][0-9]-x86)
                            ;;
                        android-[1-9][0-9]-x86_64)
                            ;;
                        *) abort 1 "you have set environment variable NDKPKG_DEFAULT_TARGET=$NDKPKG_DEFAULT_TARGET , but it is an invalid android spec."
                    esac

                    printf '%s\n' "$NDKPKG_DEFAULT_TARGET/$1"
                else
                    case $2 in
                        android-[1-9][0-9]-armeabi-v7a)
                            ;;
                        android-[1-9][0-9]-arm64-v8a)
                            ;;
                        android-[1-9][0-9]-x86)
                            ;;
                        android-[1-9][0-9]-x86_64)
                            ;;
                        *) abort 1 "you have specified --target=$2 argument, but it is an invalid android spec."
                    esac

                    printf '%s\n' "$2/$1"
                fi
            else
                abort 1 "invalid package name: $1"
            fi
    esac
}

inspect_install_arguments() {
    LOG_LEVEL_QUIET=0
    LOG_LEVEL_NORMAL=1
    LOG_LEVEL_VERBOSE=2
    LOG_LEVEL_VERY_VERBOSE=3

    unset PROFILE

    unset LOG_LEVEL

    unset BUILD_NJOBS

    unset ENABLE_LTO

    unset ENABLE_STRIP

    unset ENABLE_CCACHE

    unset REQUEST_TO_UPGRADE_IF_POSSIBLE

    unset REQUEST_TO_EXPORT_COMPILE_COMMANDS_JSON

    unset REQUEST_TO_KEEP_SESSION_DIR

    unset REQUEST_TO_CREATE_FULLY_STATICALLY_LINKED_EXECUTABLE

    unset SPECIFIED_FORMULA_SEARCH_DIRS

    unset SPECIFIED_PACKAGE_LIST

    unset SPECIFIED_TARGET

    unset ANDROID_NDK_HOME
    unset ANDROID_NDK_REVISION

    unset DUMP_ENV
    unset DUMP_HTTP
    unset DUMP_UPPM
    unset DUMP_NDK
    unset DUMP_SED
    unset DUMP_FORMULA

    unset VERBOSE_GO
    unset VERBOSE_CARGO
    unset VERBOSE_MESON
    unset VERBOSE_NINJA
    unset VERBOSE_GMAKE
    unset VERBOSE_CMAKE
    unset VERBOSE_XMAKE

    unset DEBUG_CC
    unset DEBUG_LD
    unset DEBUG_GO
    unset DEBUG_CARGO
    unset DEBUG_GMAKE
    unset DEBUG_CMAKE
    unset DEBUG_XMAKE
    unset DEBUG_PKG_CONFIG

    while [ -n "$1" ]
    do
        case $1 in
            -q) LOG_LEVEL=0 ;;
            -v) LOG_LEVEL=2

                DUMP_ENV=1
                DUMP_HTTP=1
                DUMP_UPPM=1
                DUMP_NDK=1
                DUMP_SED=1
                DUMP_FORMULA=1

                VERBOSE_GO=1
                VERBOSE_CARGO=1
                VERBOSE_MESON=1
                VERBOSE_NINJA=1
                VERBOSE_GMAKE=1
                VERBOSE_CMAKE=1
                VERBOSE_XMAKE=1
                ;;
            -x) LOG_LEVEL=3

                DUMP_ENV=1
                DUMP_HTTP=1
                DUMP_UPPM=1
                DUMP_NDK=1
                DUMP_SED=1
                DUMP_FORMULA=1

                VERBOSE_MESON=1
                VERBOSE_NINJA=1
                VERBOSE_GMAKE=1
                VERBOSE_CMAKE=1
                VERBOSE_XMAKE=1

                DEBUG_CC=1
                DEBUG_LD=1
                DEBUG_GO=1
                DEBUG_CARGO=1
                DEBUG_GMAKE=1
                DEBUG_CMAKE=1
                DEBUG_XMAKE=1
                DEBUG_PKG_CONFIG=1
                ;;
            -v-env)
                DUMP_ENV=1
                ;;
            -v-http)
                DUMP_HTTP=1
                ;;
            -v-uppm)
                DUMP_UPPM=1
                ;;
            -v-ndk)
                DUMP_NDK=1
                ;;
            -v-formula)
                DUMP_FORMULA=1
                ;;
            -v-go)
                VERBOSE_GO=1
                ;;
            -v-cargo)
                VERBOSE_CARGO=1
                ;;
            -v-meson)
                VERBOSE_MESON=1
                ;;
            -v-ninja)
                VERBOSE_NINJA=1
                ;;
            -v-gmake)
                VERBOSE_GMAKE=1
                ;;
            -v-cmake)
                VERBOSE_CMAKE=1
                ;;
            -v-xmake)
                VERBOSE_XMAKE=1
                ;;
            -x-sh)
                set -x
                ;;
            -x-cc)
                DEBUG_CC=1
                ;;
            -x-ld)
                DEBUG_LD=1
                ;;
            -x-go)
                DEBUG_GO=1
                ;;
            -x-cargo)
                DEBUG_CARGO=1
                ;;
            -x-gmake)
                DEBUG_GMAKE=1
                ;;
            -x-cmake)
                DEBUG_CMAKE=1
                ;;
            -x-xmake)
                DEBUG_XMAKE=1
                ;;
            -x-pkg-config)
                DEBUG_PKG_CONFIG=1
                ;;
            --disable-ccache)
                ENABLE_CCACHE=0
                ;;
            --enable-lto)
                ENABLE_LTO=1
                ;;
            --enable-strip)
                ENABLE_STRIP=all
                ;;
            --enable-strip=*)
                ENABLE_STRIP="${1#*=}"
                case $ENABLE_STRIP in
                    no|all|debug|unneeded) ;;
                    *)  abort 1 "--strip=<VALUE>, VALUE must be one of no, all, debug, unneeded"
                esac
                ;;
            --target=*)
                SPECIFIED_TARGET="${1#*=}"
                ;;
            --profile=*)
                PROFILE="${1#*=}"
                case $PROFILE in
                    '') abort 1 "--profile=<VALUE>, VALUE should not be empty." ;;
                    debug|release) ;;
                    *)  abort 1 "--profile=<VALUE>, VALUE must be either debug or release" ;;
                esac
                ;;
            --ndk-home=*)
                ANDROID_NDK_HOME="${1#*=}"
                ;;
            --ndk-revision=*)
                ANDROID_NDK_REVISION="${1#*=}"
                case $ANDROID_NDK_REVISION in
                    [1-2][0-9][bcd])
                        ;;
                    *)  abort 1 "invalid Android NDK revision : $ANDROID_NDK_REVISION, example values are 28c, 27d, 26d, 25c, etc. For more details, please visit https://developer.android.com/ndk/downloads/revision_history"
                esac
                ;;
            --static)
                REQUEST_TO_CREATE_FULLY_STATICALLY_LINKED_EXECUTABLE=1
                ;;
            -j) shift
                isInteger "$1" || abort 1 "-j <N>, <N> must be an integer."
                BUILD_NJOBS="$1"
                ;;
            -I) shift
                [ -z "$1" ] && abort 1 "-I <FORMULA-SEARCH-DIR> , <FORMULA-SEARCH-DIR> is unspecified."
                [ -e "$1" ] || abort 1 "'$1' was expected to be exist, but it was not."
                [ -d "$1" ] || abort 1 "'$1' was expected to be a directory, but it was not."
                FORMULA_SEARCH_DIR="$(realpath "$1")"
                SPECIFIED_FORMULA_SEARCH_DIRS="$SPECIFIED_FORMULA_SEARCH_DIRS:$FORMULA_SEARCH_DIR"
                ;;
            -K) REQUEST_TO_KEEP_SESSION_DIR=1 ;;
            -U) REQUEST_TO_UPGRADE_IF_POSSIBLE=1 ;;
            -E) REQUEST_TO_EXPORT_COMPILE_COMMANDS_JSON=1 ;;

            -y) ;;

            -*) abort 1 "unrecognized option: $1" ;;

            *)  SPECIFIED_PACKAGE_LIST="$SPECIFIED_PACKAGE_LIST $1"
        esac
        shift
    done

    #########################################################################################

    if [ -n "$ANDROID_NDK_HOME" ] && [ -n "$ANDROID_NDK_REVISION" ] ; then
        abort 1 "--ndk-home=<ANDROID-NDK-HOME> and -r$ANDROID_NDK_REVISION options are mutually exclusive. You can only specify one of them."
    fi

    #########################################################################################

    if [ -z "$NDKPKG_FORMULA_SEARCH_DIRS" ] ; then
        NDKPKG_FORMULA_SEARCH_DIRS="${SPECIFIED_FORMULA_SEARCH_DIRS#:}"
    else
        NDKPKG_FORMULA_SEARCH_DIRS="${SPECIFIED_FORMULA_SEARCH_DIRS#:}:$NDKPKG_FORMULA_SEARCH_DIRS"
    fi

    #########################################################################################

    unset SPECIFIED_PACKAGE_SPEC_LIST

    for PACKAGE in $SPECIFIED_PACKAGE_LIST
    do
        SPECIFIED_PACKAGE_SPEC_LIST="$SPECIFIED_PACKAGE_SPEC_LIST $(inspect_package_spec_list "$PACKAGE" "$SPECIFIED_TARGET")"
    done

    SPECIFIED_PACKAGE_SPEC_LIST=${SPECIFIED_PACKAGE_SPEC_LIST#' '}

    #########################################################################################

    if [ "$LOG_LEVEL" = 0 ] ; then
        exec 1>/dev/null
        exec 2>&1
    else
        if [ -z "$LOG_LEVEL" ] ; then
            LOG_LEVEL=1
        fi
    fi

    #########################################################################################

    if [ -z "$PROFILE" ] ; then
        PROFILE=release
    fi

    #########################################################################################

    if [ -z "$ENABLE_STRIP" ] ; then
        case $PROFILE in
            debug)   ENABLE_STRIP=no  ;;
            release) ENABLE_STRIP=all ;;
        esac
    fi

    #########################################################################################

    # these environment variables are not used by this script
    # https://cmake.org/cmake/help/latest/envvar/MACOSX_DEPLOYMENT_TARGET.html
    unset   MACOSX_DEPLOYMENT_TARGET
    unset IPHONEOS_DEPLOYMENT_TARGET
    unset  WATCHOS_DEPLOYMENT_TARGET

    # https://www.real-world-systems.com/docs/xcrun.1.html
    unset SDKROOT

    # https://stackoverflow.com/questions/18476490/what-is-purpose-of-target-arch-variable-in-makefiles
    unset TARGET_ARCH

    unset LIBS

    # these environment variables are overridden by this script
    unset        CC_FOR_BUILD
    unset      OBJC_FOR_BUILD
    unset       CXX_FOR_BUILD
    unset       CPP_FOR_BUILD
    unset        AS_FOR_BUILD
    unset        AR_FOR_BUILD
    unset    RANLIB_FOR_BUILD
    unset        LD_FOR_BUILD
    unset        NM_FOR_BUILD
    unset      SIZE_FOR_BUILD
    unset     STRIP_FOR_BUILD
    unset   STRINGS_FOR_BUILD
    unset   OBJDUMP_FOR_BUILD
    unset   OBJCOPY_FOR_BUILD
    unset   READELF_FOR_BUILD
    unset   SYSROOT_FOR_BUILD

    unset    CFLAGS_FOR_BUILD
    unset  CXXFLAGS_FOR_BUILD
    unset OBJCFLAGS_FOR_BUILD
    unset   LDFLAGS_FOR_BUILD

    #########################################################################################

    if [ "$DEBUG_CC" = 1 ] ; then
        # this environment variable is used by wrapper-target-*
        export NDKPKG_VERBOSE=1
    else
        unset  NDKPKG_VERBOSE
    fi

    #########################################################################################

    setup_android_ndk_env "$ANDROID_NDK_REVISION" "$ANDROID_NDK_HOME"
}

__install_the_given_packages() {
    inspect_install_arguments "$@"

    [ -z "$SPECIFIED_PACKAGE_SPEC_LIST" ] && abort 1 "$NDKPKG_ARG0 install <PACKAGE-SPEC|PACKAGE-NAME>..., <|PACKAGE-SPEC|PACKAGE-NAME> is unspecified."

    #########################################################################################

    SESSION_DIR="$NDKPKG_HOME/run/$$"

    rm -rf     "$SESSION_DIR"
    install -d "$SESSION_DIR"

    #########################################################################################

    # 1. check if has circle
    # 2. backup formulas
    # 3. cache variables

    for SPECIFIED_PACKAGE_SPEC in $SPECIFIED_PACKAGE_SPEC_LIST
    do
        PACKAGE_NAME_STACK="${SPECIFIED_PACKAGE_SPEC##*/}"

        while [ -n "$PACKAGE_NAME_STACK" ]
        do
            case $PACKAGE_NAME_STACK in
                *\;*) PACKAGE_NAME="${PACKAGE_NAME_STACK##*;}" ; PACKAGE_NAME_STACK="${PACKAGE_NAME_STACK%;*}" ;;
                *)    PACKAGE_NAME="${PACKAGE_NAME_STACK}"     ; PACKAGE_NAME_STACK=
            esac

            if [ -f "$SESSION_DIR/$PACKAGE_NAME.yml" ] ; then
                continue
            fi

            __load_formula_of_the_given_package "$PACKAGE_NAME"

            cp -L "$PACKAGE_FORMULA_FILEPATH" "$SESSION_DIR/$PACKAGE_NAME.yml"

            eval "PACKAGE_DEP_PKG_${PACKAGE_NAME_UPPERCASE_UNDERSCORE}='$PACKAGE_DEP_PKG'"

            for DEPENDENT_PACKAGE_NAME in $PACKAGE_DEP_PKG
            do
                if [ "$DEPENDENT_PACKAGE_NAME" = "$PACKAGE_NAME" ] ; then
                    abort 1 "package '$PACKAGE_NAME' depends itself."
                fi

                if [ -z "$PACKAGE_NAME_STACK" ] ; then
                    PACKAGE_NAME_STACK="$DEPENDENT_PACKAGE_NAME"
                else
                    PACKAGE_NAME_STACK="$PACKAGE_NAME_STACK;$DEPENDENT_PACKAGE_NAME"
                fi
            done
        done
    done

    #########################################################################################

    for SPECIFIED_PACKAGE_SPEC in $SPECIFIED_PACKAGE_SPEC_LIST
    do
        TARGET_PLATFORM_SPEC="${SPECIFIED_PACKAGE_SPEC%/*}"

        TARGET_PLATFORM_NAME=
        TARGET_PLATFORM_VERS=
        TARGET_PLATFORM_ARCH=

        TARGET_PLATFORM_NAME="$(printf '%s\n' "$TARGET_PLATFORM_SPEC" | cut -d- -f1)"
        TARGET_PLATFORM_VERS="$(printf '%s\n' "$TARGET_PLATFORM_SPEC" | cut -d- -f2)"
        TARGET_PLATFORM_ARCH="$(printf '%s\n' "$TARGET_PLATFORM_SPEC" | cut -c 12-)"

        ##################################################################

        REQUESTED_PACKAGE_NAME_LIST=

        PACKAGE_NAME_STACK="${SPECIFIED_PACKAGE_SPEC##*/}"

        while [ -n "$PACKAGE_NAME_STACK" ]
        do
            case $PACKAGE_NAME_STACK in
                *\;*) PACKAGE_NAME="${PACKAGE_NAME_STACK##*;}" ; PACKAGE_NAME_STACK="${PACKAGE_NAME_STACK%;*}" ;;
                *)    PACKAGE_NAME="${PACKAGE_NAME_STACK}"     ; PACKAGE_NAME_STACK=
            esac

            ##################################################################

            REQUESTED_PACKAGE_NAME_LIST2="$PACKAGE_NAME"

            for item in $REQUESTED_PACKAGE_NAME_LIST
            do
                [ "$item" = "$PACKAGE_NAME" ] && continue
                REQUESTED_PACKAGE_NAME_LIST2="$REQUESTED_PACKAGE_NAME_LIST2 $item"
            done

            REQUESTED_PACKAGE_NAME_LIST="$REQUESTED_PACKAGE_NAME_LIST2"

            ##################################################################

            PACKAGE_NAME_UPPERCASE_UNDERSCORE="$(printf '%s\n' "$PACKAGE_NAME" | tr a-z A-Z | tr '@+-.' '_')"

            for item in $(eval echo \$PACKAGE_DEP_PKG_"${PACKAGE_NAME_UPPERCASE_UNDERSCORE}")
            do
                if [ -z "$PACKAGE_NAME_STACK" ] ; then
                    PACKAGE_NAME_STACK="$item"
                else
                    PACKAGE_NAME_STACK="$PACKAGE_NAME_STACK;$item"
                fi
            done
        done

        ##################################################################

        for PACKAGE_NAME in $REQUESTED_PACKAGE_NAME_LIST
        do
            PACKAGE_SPEC="$TARGET_PLATFORM_SPEC/$PACKAGE_NAME"

            if is_package_installed "$PACKAGE_SPEC" ; then
                if [ "$UPGRAGE" = 1 ] ; then
                    if is_package__outdated "$PACKAGE_SPEC" ; then
                        (__install_the_given_package "$PACKAGE_SPEC")
                    else
                        if [ "$LOG_LEVEL" -ne 0 ] ; then
                            printf "$COLOR_GREEN%-10s$COLOR_OFF already have been installed and is up-to-date.\n" "$PACKAGE_SPEC"
                        fi
                    fi
                else
                    if [ "$LOG_LEVEL" -ne 0 ] ; then
                        printf "$COLOR_GREEN%-10s$COLOR_OFF already have been installed.\n" "$PACKAGE_SPEC"
                    fi
                fi
            else
                (__install_the_given_package "$PACKAGE_SPEC")
            fi
        done
    done

    #########################################################################################

    if [ "$REQUEST_TO_KEEP_SESSION_DIR" != 1 ] ; then
        rm -rf "$SESSION_DIR"
    fi
}

# https://www.gnu.org/software/gettext/manual/html_node/config_002eguess.html
# https://git.savannah.gnu.org/cgit/config.git/tree/
  __update_config_sub_guess() {
    UPDATE_GNU_CONFIG_OLDCWD="$PWD"

    run cd "$SESSION_DIR"

    if [ -f config/config.sub ] && [ -f config/config.guess ] ; then
        CONFIG_FILE_DIR="$SESSION_DIR/config"
    else
        if [    -d config ] ; then
            rm -rf config
        fi

        if run git_checkout https://github.com/leleliu008/gnu-config --depth=1 -C config ; then
            CONFIG_FILE_DIR="$SESSION_DIR/config"
        elif run git clone --depth 1 https://git.savannah.gnu.org/git/config.git ; then
            CONFIG_FILE_DIR="$SESSION_DIR/config"
        else
            if  run curl -L -o _config.sub   "'https://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.sub;hb=HEAD'" &&
                sh _config.sub x86_64-pc-linux &&
                run curl -L -o _config.guess "'https://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.guess;hb=HEAD'" &&
                sh _config.guess > /dev/null ; then
                run chmod +x _config.guess
                run chmod +x _config.sub
                run mv _config.guess config.guess
                run mv _config.sub   config.sub
                CONFIG_FILE_DIR="$SESSION_DIR"
            elif run curl -L -o _config.sub   'https://git.savannah.gnu.org/cgit/config.git/plain/config.sub' &&
                sh _config.sub x86_64-pc-linux &&
                run curl -L -o _config.guess 'https://git.savannah.gnu.org/cgit/config.git/plain/config.guess' &&
                sh _config.guess > /dev/null ; then
                run chmod +x _config.guess
                run chmod +x _config.sub
                run mv _config.guess config.guess
                run mv _config.sub   config.sub
                CONFIG_FILE_DIR="$SESSION_DIR"
            else
                CONFIG_FILE_DIR="$NDKPKG_CORE_DIR"
            fi
        fi
    fi

    run cd "$UPDATE_GNU_CONFIG_OLDCWD"

    find -type f -name config.sub   -exec cp -vf "$CONFIG_FILE_DIR/config.sub"   {} \;
    find -type f -name config.guess -exec cp -vf "$CONFIG_FILE_DIR/config.guess" {} \;
}

# should run in subshell
install_the_given_native_package() {
    [ -z "$1" ] && abort 1 "install_the_given_native_package <PACKAGE-NAME> , <PACKAGE-NAME> is unspecified."

    unset PACKAGE_SRC_URL
    unset PACKAGE_SRC_URI
    unset PACKAGE_SRC_SHA

    unset PACKAGE_DEP_PKG
    unset PACKAGE_DEP_AUX
    unset PACKAGE_DEP_RUN

    unset PACKAGE_DOPATCH
    unset PACKAGE_INSTALL
    unset PACKAGE_DOTWEAK

    if [ "$1" = 'perl-XML-Parser' ] ; then
        native_package_info_perl_XML_Parser
    else
        native_package_info_$1
    fi

    #########################################################################################

    for PACKAGE_DEPENDENCY in $PACKAGE_DEP_PKG
    do
        (install_the_given_native_package "$PACKAGE_DEPENDENCY")
    done

    #########################################################################################

    printf '\n%b\n' "${COLOR_PURPLE}=>> install native package : $1${COLOR_OFF}"

    if [ -f "$NATIVE_PACKAGE_INSTALLED_ROOT/$1/receipt.txt" ] ; then
        note "native package '$1' already has been installed, skipped."
        return 0
    fi

    #########################################################################################

    for UPPM_PACKAGE_NAME in $PACKAGE_DEP_AUX
    do
        run "$UPPM" install "$UPPM_PACKAGE_NAME" "$UPPM_INSTALL_ARGS"

        UPPM_PACKAGE_INSTALLED_DIR="$UPPM_HOME/installed/$UPPM_PACKAGE_NAME"

        if [ -d  "$UPPM_PACKAGE_INSTALLED_DIR/bin" ] ; then
            PATH="$UPPM_PACKAGE_INSTALLED_DIR/bin:$PATH"
        fi

        if [ -d  "$UPPM_PACKAGE_INSTALLED_DIR/sbin" ] ; then
            PATH="$UPPM_PACKAGE_INSTALLED_DIR/sbin:$PATH"
        fi
    done

    #########################################################################################

    PACKAGE_INSTALL_UTS=
    PACKAGE_INSTALL_UTS="$(date +%s)"

    PACKAGE_INSTALL_SHA=
    PACKAGE_INSTALL_SHA="$(
{
    sha256sum <<EOF
$1:$PACKAGE_SRC_URL:$$:$PACKAGE_INSTALL_UTS
EOF
} | cut -d ' ' -f1)"

    #########################################################################################

    PACKAGE_INSTALL_DIR="$NATIVE_PACKAGE_INSTALLED_ROOT/$PACKAGE_INSTALL_SHA"

    PACKAGE_SRC_FILETYPE="$(filetype_from_url "$PACKAGE_SRC_URL")"
    PACKAGE_SRC_FILENAME="$PACKAGE_SRC_SHA$PACKAGE_SRC_FILETYPE"
    PACKAGE_SRC_FILEPATH="$NDKPKG_DOWNLOADS_DIR/$PACKAGE_SRC_FILENAME"

    PACKAGE_WORKING_DIR="$SESSION_DIR/native/$1"

    #########################################################################################

    # override the default search directory (usually /usr/lib/pkgconfig:/usr/share/pkgconfig)
    # because we only want to use our own
    export PKG_CONFIG_LIBDIR="$PACKAGE_WORKING_DIR/lib/pkgconfig"
    export PKG_CONFIG_PATH="$PACKAGE_WORKING_DIR/lib/pkgconfig:$PKG_CONFIG_PATH"
    export ACLOCAL_PATH="$PACKAGE_WORKING_DIR/share/aclocal"
    export CPPFLAGS="-I$PACKAGE_WORKING_DIR/include $CPPFLAGS"
    export LDFLAGS="-L$PACKAGE_WORKING_DIR/lib -Wl,-rpath,$PACKAGE_INSTALL_DIR/lib $LDFLAGS"

    for DEPENDENT_PACKAGE_NAME in $PACKAGE_DEP_PKG
    do
        DEPENDENT_PACKAGE_INSTALLED_DIR="$NATIVE_PACKAGE_INSTALLED_ROOT/$DEPENDENT_PACKAGE_NAME"

        if [ -d  "$DEPENDENT_PACKAGE_INSTALLED_DIR/include" ] ; then
            CPPFLAGS="-I$DEPENDENT_PACKAGE_INSTALLED_DIR/include $CPPFLAGS"
        fi

        if [ -d  "$DEPENDENT_PACKAGE_INSTALLED_DIR/lib" ] ; then
            LDFLAGS="-L$DEPENDENT_PACKAGE_INSTALLED_DIR/lib -Wl,-rpath,$DEPENDENT_PACKAGE_INSTALLED_DIR/lib $LDFLAGS"
        fi

        if [ -d  "$DEPENDENT_PACKAGE_INSTALLED_DIR/bin" ] ; then
            PATH="$DEPENDENT_PACKAGE_INSTALLED_DIR/bin:$PATH"
        fi

        if [ -d  "$DEPENDENT_PACKAGE_INSTALLED_DIR/sbin" ] ; then
            PATH="$DEPENDENT_PACKAGE_INSTALLED_DIR/sbin:$PATH"
        fi

        if [ -d          "$DEPENDENT_PACKAGE_INSTALLED_DIR/share/aclocal" ] ; then
            ACLOCAL_PATH="$DEPENDENT_PACKAGE_INSTALLED_DIR/share/aclocal:$ACLOCAL_PATH"
        fi

        for d in lib share
        do
            DEPENDENT_PACKAGE_PKGCONF_DIR="$DEPENDENT_PACKAGE_INSTALLED_DIR/$d/pkgconfig"

            if [ -d "$DEPENDENT_PACKAGE_PKGCONF_DIR" ] ; then
                PKG_CONFIG_PATH="$DEPENDENT_PACKAGE_PKGCONF_DIR:$PKG_CONFIG_PATH"
            fi
        done
    done

    #########################################################################################

    unset    CFLAGS_FOR_BUILD
    unset  CXXFLAGS_FOR_BUILD
    unset  CPPFLAGS_FOR_BUILD
    unset   LDFLAGS_FOR_BUILD

    #########################################################################################

    wfetch "$PACKAGE_SRC_URL" --uri="$PACKAGE_SRC_URI" --sha256="$PACKAGE_SRC_SHA" -o "$PACKAGE_SRC_FILEPATH"

    #########################################################################################

    run install -d "$PACKAGE_WORKING_DIR/src"
    run cd         "$PACKAGE_WORKING_DIR/src"

    #########################################################################################

    run bsdtar xf "$PACKAGE_SRC_FILEPATH" --strip-components=1 --no-same-owner

    #########################################################################################

    if [ -n  "$PACKAGE_DOPATCH" ] ; then
        eval "$PACKAGE_DOPATCH"
    fi

    #########################################################################################

    if [ -z "$PACKAGE_INSTALL" ] ; then
        abort 1 "PACKAGE_INSTALL variable is not set for native package '$1'"
    fi

    case "${PACKAGE_INSTALL%% *}" in
        configure)
            __update_config_sub_guess
            PACKAGE_INSTALL="run ./$PACKAGE_INSTALL --prefix=$PACKAGE_INSTALL_DIR && run gmake --jobs=$BUILD_NJOBS && run gmake install"
            ;;
        config)
            PACKAGE_INSTALL="run ./$PACKAGE_INSTALL --prefix=$PACKAGE_INSTALL_DIR && run gmake --jobs=$BUILD_NJOBS && run gmake install_sw"
            ;;
        perl)
            PACKAGE_INSTALL="run $PACKAGE_INSTALL && run gmake --jobs=$BUILD_NJOBS && run gmake install && run install -d $PACKAGE_INSTALL_DIR"
            ;;
        cmake)
            PACKAGE_INSTALL="run $PACKAGE_INSTALL -DCMAKE_INSTALL_PREFIX=$PACKAGE_INSTALL_DIR -DENABLE_TESTING=OFF -DCMAKE_VERBOSE_MAKEFILE=ON -DCMAKE_BUILD_TYPE=Release -G Ninja -S . -B build.d && run cmake --build build.d -- -j$BUILD_NJOBS && run cmake --install build.d"
            ;;
    esac

    eval "$PACKAGE_INSTALL"

    #########################################################################################

    run cd "$PACKAGE_INSTALL_DIR"

    #########################################################################################

    if [ -n  "$PACKAGE_DOTWEAK" ] ; then
        eval "$PACKAGE_DOTWEAK"
    fi

    #########################################################################################

    run cd "$PACKAGE_INSTALL_DIR"

    #########################################################################################

    cat > buildon.yml <<EOF
os-arch: $NATIVE_PLATFORM_ARCH
os-kind: $NATIVE_PLATFORM_KIND
os-type: $NATIVE_PLATFORM_TYPE
os-libc: $NATIVE_PLATFORM_LIBC
os-code: $NATIVE_PLATFORM_CODE
os-name: $NATIVE_PLATFORM_NAME
os-vers: $NATIVE_PLATFORM_VERS
os-ncpu: $NATIVE_PLATFORM_NCPU
os-euid: $NATIVE_PLATFORM_EUID
os-egid: $NATIVE_PLATFORM_EGID
EOF

    #########################################################################################

    cat > toolchain.txt <<EOF
     CC='$CC'
    CXX='$CXX'
     AS='$AS'
     LD='$LD'
     AR='$AR'
 RANLIB='$RANLIB'
SYSROOT='$SYSROOT'
EOF

    #########################################################################################

    cat > receipt.txt <<EOF
PACKAGE_SRC_URL='$PACKAGE_SRC_URL'
PACKAGE_SRC_URI='$PACKAGE_SRC_URI'
PACKAGE_SRC_SHA='$PACKAGE_SRC_SHA'

PACKAGE_DEP_PKG='$PACKAGE_DEP_PKG'
PACKAGE_DEP_AUX='$PACKAGE_DEP_AUX'
PACKAGE_DEP_RUN='$PACKAGE_DEP_RUN'

PACKAGE_DOPATCH='$PACKAGE_DOPATCH'
PACKAGE_DOTWEAK='$PACKAGE_DOTWEAK'
PACKAGE_INSTALL='$PACKAGE_INSTALL'
PACKAGE_INSTALL_UTS='$PACKAGE_INSTALL_UTS'
EOF

    #########################################################################################

    run cd "$NATIVE_PACKAGE_INSTALLED_ROOT"
    run ln -s -f -T "$PACKAGE_INSTALL_SHA" "$1"
}

native_package_info_libz() {
    PACKAGE_SRC_URL='https://zlib.net/zlib-1.3.1.tar.gz'
    PACKAGE_SRC_SHA='9a93b2b7dfdac77ceba5a558a580e74667dd6fede4585b91eefb60f03b72df23'
    PACKAGE_DEP_AUX='gsed cmake ninja'
    PACKAGE_DOPATCH='gsed -i "s|/share/pkgconfig|/lib/pkgconfig|" CMakeLists.txt'
    PACKAGE_INSTALL='cmake -DZLIB_BUILD_EXAMPLES=OFF -G Ninja'
}

native_package_info_libopenssl() {
    PACKAGE_SRC_URL='https://www.openssl.org/source/openssl-3.3.1.tar.gz'
    PACKAGE_SRC_SHA='777cd596284c883375a2a7a11bf5d2786fc5413255efab20c50d6ffe6d020b7e'
    PACKAGE_DEP_AUX='perl gmake'
    PACKAGE_DOPATCH='
    case $NATIVE_PLATFORM_ARCH in
        armv7l) gsed -i "s|armv7-a|armv7-a+fp|g" util/perl/OpenSSL/config.pm
    esac'
    PACKAGE_INSTALL='config no-tests no-ssl3 no-ssl3-method no-zlib --libdir=lib --openssldir=etc/ssl'
    # https://github.com/openssl/openssl/blob/master/INSTALL.md
}

native_package_info_libtool() {
    PACKAGE_SRC_URL='https://ftp.gnu.org/gnu/libtool/libtool-2.5.4.tar.xz'
    PACKAGE_SRC_SHA='f81f5860666b0bc7d84baddefa60d1cb9fa6fceb2398cc3baca6afaa60266675'
    PACKAGE_INSTALL='configure --enable-ltdl-install'
    PACKAGE_DEP_AUX='gm4 gmake'
    PACKAGE_DOTWEAK='
run ln -s libtool    bin/glibtool
run ln -s libtoolize bin/glibtoolize
'
}

native_package_info_autoconf() {
    PACKAGE_SRC_URL='https://ftp.gnu.org/gnu/autoconf/autoconf-2.72.tar.gz'
    PACKAGE_SRC_SHA='afb181a76e1ee72832f6581c0eddf8df032b83e2e0239ef79ebedc4467d92d6e'
    PACKAGE_DEP_AUX='perl gm4 gmake'
    PACKAGE_DEP_RUN='perl gm4'
    PACKAGE_INSTALL='configure'
}

native_package_info_automake() {
    PACKAGE_SRC_URL='https://ftp.gnu.org/gnu/automake/automake-1.17.tar.xz'
    PACKAGE_SRC_SHA='8920c1fc411e13b90bf704ef9db6f29d540e76d232cb3b2c9f4dc4cc599bd990'
    PACKAGE_DEP_AUX='perl gmake'
    PACKAGE_DEP_RUN='perl'
    PACKAGE_DEP_PKG='autoconf'
    PACKAGE_INSTALL='configure'
}

native_package_info_texinfo() {
    PACKAGE_SRC_URL='https://ftp.gnu.org/gnu/texinfo/texinfo-7.2.tar.xz'
    PACKAGE_SRC_SHA='0329d7788fbef113fa82cb80889ca197a344ce0df7646fe000974c5d714363a6'
    PACKAGE_DEP_AUX='perl gmake'
    PACKAGE_DEP_RUN='perl'
    PACKAGE_DOPATCH='
gsed -i "/libintl/d" tp/Texinfo/XS/parsetexi/api.c

export PERL_EXT_CC="$CC"
export PERL_EXT_CFLAGS="$CFLAGS"
export PERL_EXT_CPPFLAGS="$CPPFLAGS"
export PERL_EXT_LDFLAGS="$LDFLAGS"
'
    PACKAGE_INSTALL='configure --with-included-regex --enable-threads=posix --disable-nls'
}

native_package_info_help2man() {
    PACKAGE_SRC_URL='https://ftp.gnu.org/gnu/help2man/help2man-1.49.3.tar.xz'
    PACKAGE_SRC_SHA='4d7e4fdef2eca6afe07a2682151cea78781e0a4e8f9622142d9f70c083a2fd4f'
    PACKAGE_DEP_AUX='perl gmake'
    PACKAGE_DEP_RUN='perl'
    PACKAGE_INSTALL='configure'
}

native_package_info_libexpat() {
    PACKAGE_SRC_URL='https://github.com/libexpat/libexpat/releases/download/R_2_6_4/expat-2.6.4.tar.xz'
    PACKAGE_SRC_SHA='a695629dae047055b37d50a0ff4776d1d45d0a4c842cf4ccee158441f55ff7ee'
    PACKAGE_DEP_AUX='gmake'
    PACKAGE_INSTALL='configure --disable-dependency-tracking --enable-static --enable-shared --without-xmlwf --without-tests --without-examples --without-docbook'
}

native_package_info_intltool() {
    PACKAGE_SRC_URL='https://launchpad.net/intltool/trunk/0.51.0/+download/intltool-0.51.0.tar.gz'
    PACKAGE_SRC_URI='https://fossies.org/linux/privat/intltool-0.51.0.tar.gz'
    PACKAGE_SRC_SHA='67c74d94196b153b774ab9f89b2fa6c6ba79352407037c8c14d5aeb334e959cd'
    PACKAGE_DEP_AUX='perl gmake'
    PACKAGE_DEP_RUN='perl'
    PACKAGE_DEP_PKG='libexpat perl-XML-Parser'
    PACKAGE_INSTALL='configure'
}

native_package_info_perl_XML_Parser() {
    PACKAGE_SRC_URL='https://cpan.metacpan.org/authors/id/T/TO/TODDR/XML-Parser-2.47.tar.gz'
    PACKAGE_SRC_SHA='ad4aae643ec784f489b956abe952432871a622d4e2b5c619e8855accbfc4d1d8'
    PACKAGE_DEP_AUX='perl gmake'
    PACKAGE_DEP_RUN='perl'
    PACKAGE_DEP_PKG='libexpat'
    PACKAGE_DOPATCH='
run export EXPATLIBPATH="$NATIVE_PACKAGE_INSTALLED_ROOT/libexpat/lib"
run export EXPATINCPATH="$NATIVE_PACKAGE_INSTALLED_ROOT/libexpat/include"
run gsed -i "\"/check_lib/a not_execute,\"" Makefile.PL
'
    PACKAGE_INSTALL='perl Makefile.PL'
}

native_package_info_libiconv() {
    PACKAGE_SRC_URL='https://ftp.gnu.org/gnu/libiconv/libiconv-1.17.tar.gz'
    PACKAGE_SRC_SHA='8f74213b56238c85a50a5329f77e06198771e70dd9a739779f4c02f65d971313'
    PACKAGE_DEP_AUX='gmake'
    PACKAGE_INSTALL='configure --disable-dependency-tracking --enable-static --enable-shared --enable-extra-encodings'
}

native_package_info_libxml2() {
    PACKAGE_SRC_URL='https://download.gnome.org/sources/libxml2/2.13/libxml2-2.13.5.tar.xz'
    PACKAGE_SRC_URI='https://distfiles.macports.org/libxml2/libxml2-2.13.5.tar.xz'
    PACKAGE_SRC_SHA='74fc163217a3964257d3be39af943e08861263c4231f9ef5b496b6f6d4c7b2b6'
    PACKAGE_DEP_PKG='libz libiconv'
    PACKAGE_DEP_AUX='gmake'
    PACKAGE_INSTALL='configure --with-zlib --with-python --with-iconv="$NATIVE_PACKAGE_INSTALLED_ROOT/libiconv" --without-lzma --without-readline --without-coverage --without-debug --enable-ipv6 --enable-static --enable-shared LIBS=-liconv'
}

native_package_info_itstool() {
    PACKAGE_SRC_URL='https://github.com/itstool/itstool/archive/2.0.7.tar.gz'
    PACKAGE_SRC_SHA='fba78a37dc3535e4686c7f57407b97d03c676e3a57beac5fb2315162b0cc3176'
    PACKAGE_DEP_AUX='perl python3 gmake'
    PACKAGE_DEP_RUN='perl python3'
    PACKAGE_DEP_PKG='libxml2 autoconf automake'
    PACKAGE_INSTALL='configure'
    PACKAGE_DOPATCH='
    run autoreconf -ivf
    export PYTHON="$(command -v python3)"
    export PYTHONPATH="$NATIVE_PACKAGE_INSTALLED_ROOT/libxml2/lib/python3.11/site-packages"
    '
    PACKAGE_DOTWEAK='
run mv bin/itstool bin/itstool.py
cat > bin/itstool <<EOF
#!/bin/sh
export PYTHONPATH="$PYTHONPATH"
exec "$PYTHON" "$PACKAGE_INSTALL_DIR/bin/itstool.py" "\$@"
EOF
run chmod +x bin/itstool
    '
}

# }}}
##############################################################################
# {{{ __install_the_given_package


__install_the_given_package_onexit() {
    is_package_installed "$PACKAGE_SPEC" || {
        abort 1 "package installation failure: $PACKAGE_SPEC\n"

        if [ -n "$PACKAGE_WORKING_DIR"] ; then
            printf '%b\n' "${COLOR_RED}you would probably want to figure out want had happeded, please change to the working directory: $PACKAGE_WORKING_DIR${COLOR_OFF}"
        fi
    }
}

# Note: this function must run in a subshell
__install_the_given_package() {
    printf '%b\n' "${COLOR_PURPLE}>>> Installation ${COLOR_OFF}${COLOR_GREEN}${1}${COLOR_OFF}${COLOR_PURPLE} start${COLOR_OFF}"

    unset PACKAGE_WORKING_DIR

    trap  __install_the_given_package_onexit EXIT

    case $TARGET_PLATFORM_ARCH in
        armeabi-v7a)
            TARGET_PLATFORM_ABI='armeabi-v7a'
            TARGET_PLATFORM_ARCH='armv7a'
            TARGET_PLATFORM_NBIT=32
            ;;
        arm64-v8a)
            TARGET_PLATFORM_ABI='arm64-v8a'
            TARGET_PLATFORM_ARCH='aarch64'
            TARGET_PLATFORM_NBIT=64
            ;;
        x86)
            TARGET_PLATFORM_ABI='x86'
            TARGET_PLATFORM_ARCH='i686'
            TARGET_PLATFORM_NBIT=32
            ;;
        x86_64)
            TARGET_PLATFORM_ABI='x86_64'
            TARGET_PLATFORM_ARCH='x86_64'
            TARGET_PLATFORM_NBIT=64
            ;;
        *)  abort 1 "unsupported target arch: $TARGET_PLATFORM_ARCH"
    esac

    #########################################################################################

    if [ "$TARGET_PLATFORM_NBIT" -eq 64 ] ; then
        ANDROID_DYNAMIC_LINKER_PATH='/system/bin/linker64'
    else
        ANDROID_DYNAMIC_LINKER_PATH='/system/bin/linker'
    fi

    #########################################################################################

    if [ "$LOG_LEVEL" -ge "$LOG_LEVEL_VERBOSE" ] ; then
        cat <<EOF
      TIMESTAMP_UNIX = $TIMESTAMP_UNIX

NATIVE_PLATFORM_KIND = $NATIVE_PLATFORM_KIND
NATIVE_PLATFORM_TYPE = $NATIVE_PLATFORM_TYPE
NATIVE_PLATFORM_CODE = $NATIVE_PLATFORM_CODE
NATIVE_PLATFORM_NAME = $NATIVE_PLATFORM_NAME
NATIVE_PLATFORM_VERS = $NATIVE_PLATFORM_VERS
NATIVE_PLATFORM_ARCH = $NATIVE_PLATFORM_ARCH
NATIVE_PLATFORM_NCPU = $NATIVE_PLATFORM_NCPU
NATIVE_PLATFORM_LIBC = $NATIVE_PLATFORM_LIBC
NATIVE_PLATFORM_EUID = $NATIVE_PLATFORM_EUID
NATIVE_PLATFORM_EGID = $NATIVE_PLATFORM_EGID

TARGET_PLATFORM_VERS = $TARGET_PLATFORM_VERS
TARGET_PLATFORM_ARCH = $TARGET_PLATFORM_ARCH
TARGET_PLATFORM_ABI  = $TARGET_PLATFORM_ABI

NDKPKG_ARG0          = $NDKPKG_ARG0
NDKPKG_ARG1          = $NDKPKG_ARG1
NDKPKG_ARGV          = $NDKPKG_ARGV
NDKPKG_PATH          = $NDKPKG_PATH
NDKPKG_HOME          = $NDKPKG_HOME
NDKPKG_VERSION       = $NDKPKG_VERSION
NDKPKG_URL_TRANSFORM = $NDKPKG_URL_TRANSFORM

           LOG_LEVEL = $LOG_LEVEL
             PROFILE = $PROFILE

       ENABLE_CCACHE = $ENABLE_CCACHE
REQUEST_TO_KEEP_SESSION_DIR = $REQUEST_TO_KEEP_SESSION_DIR
REQUEST_TO_EXPORT_COMPILE_COMMANDS_JSON = $REQUEST_TO_EXPORT_COMPILE_COMMANDS_JSON
REQUEST_TO_CREATE_FULLY_STATICALLY_LINKED_EXECUTABLE = $REQUEST_TO_CREATE_FULLY_STATICALLY_LINKED_EXECUTABLE
EOF
    fi

    #########################################################################################

    step "load formula"

    PACKAGE_FORMULA_FILEPATH="$SESSION_DIR/$PACKAGE_NAME.yml"

    if [ "$DUMP_FORMULA" = 1 ] ; then
        bat --language=yaml --paging=never "$PACKAGE_FORMULA_FILEPATH"
    fi

    __load_formula_of_the_given_package "$PACKAGE_NAME" "$PACKAGE_FORMULA_FILEPATH"

    #########################################################################################

    if [ "$PACKAGE_SUPPORT_BUILD_ON_MACOS" != 1 ] && [ "$NATIVE_PLATFORM_NAME" = macos ] ; then
        abort 1 "package '$PACKAGE_NAME' is only supported built on GNU/Linux"
    fi

    #########################################################################################

    unset PACKAGE_CREATE_FULLY_STATICALLY_LINKED_EXECUTABLE
    unset PACKAGE_CREATE_MOSTLY_STATICALLY_LINKED_EXECUTABLE

    [ "$PACKAGE_PKGTYPE" = exe ] && {
        if [ "$REQUEST_TO_CREATE_FULLY_STATICALLY_LINKED_EXECUTABLE" = 1 ] ; then
            if [ "$PACKAGE_SUPPORT_CREATE_FULLY_STATICALLY_LINKED_EXECUTABLE" = 1 ] ; then
                if [ "$TARGET_PLATFORM_VERS" -ne "$ANDROID_NDK_SUPPORTED_MAX_SDK_API_LEVEL" ] ; then
                    abort 1 "You are requesting to create fully statically linked executables, but NDK only provide the libc.a for the latest Android API level $ANDROID_NDK_SUPPORTED_MAX_SDK_API_LEVEL. That's to say you're supposed to use Android API level $ANDROID_NDK_SUPPORTED_MAX_SDK_API_LEVEL to compile with this package. For more details, please read https://github.com/android/ndk/issues/2017"
                fi

                PACKAGE_CREATE_FULLY_STATICALLY_LINKED_EXECUTABLE=1
            else
                if [ "$PACKAGE_SUPPORT_CREATE_MOSTLY_STATICALLY_LINKED_EXECUTABLE" = 1 ] ; then
                    note "You are requesting to create fully statically linked executables, but package '$PACKAGE_NAME' is supposed to create dynamically linked executables, so we will downgrade to create mostly statically linked executables."
                    export PACKAGE_CREATE_MOSTLY_STATICALLY_LINKED_EXECUTABLE=1
                else
                    note "You are requesting to create fully statically linked executables, but package '$PACKAGE_NAME' is supposed to create dynamically linked executables."
                fi
            fi
        else
            if [ "$PACKAGE_SUPPORT_CREATE_MOSTLY_STATICALLY_LINKED_EXECUTABLE" = 1 ] ; then
                export PACKAGE_CREATE_MOSTLY_STATICALLY_LINKED_EXECUTABLE=1
            fi
        fi
    }

    #########################################################################################

    if [ -z "$PACKAGE_API_MIN" ] ; then
        PACKAGE_API_MIN="$ANDROID_NDK_SUPPORTED_MIN_SDK_API_LEVEL"
    fi

    if [ "$LOG_LEVEL" -ge "$LOG_LEVEL_VERBOSE" ] ; then
        cat <<EOF
supported min sdk api level: $PACKAGE_API_MIN
requested min sdk api level: $TARGET_PLATFORM_VERS
EOF
    fi

    if [ "$PACKAGE_API_MIN" -gt "$TARGET_PLATFORM_VERS" ] ; then
        abort 1 "package installation failure: '$1'\n    supported min sdk api level: $PACKAGE_API_MIN\n    requested min sdk api level: $TARGET_PLATFORM_VERS"
    fi

    #########################################################################################

    if [ "$PACKAGE_SUPPORT_BUILD_IN_PARALLEL" = 1 ] ; then
        if [ -z "$BUILD_NJOBS" ] ; then
            BUILD_NJOBS="$NATIVE_PLATFORM_NCPU"
        fi
    else
        BUILD_NJOBS=1
    fi

    #########################################################################################

    PACKAGE_INSTALL_UTS=
    PACKAGE_INSTALL_UTS="$(date +%s)"

    PACKAGE_INSTALL_SHA=
    PACKAGE_INSTALL_SHA="$(
{
    sha256sum <<EOF
$PACKAGE_SPEC:$$:$PACKAGE_INSTALL_UTS
EOF
} | cut -d ' ' -f1)"

    #########################################################################################

    PACKAGE_WORKING_DIR="$SESSION_DIR/$PACKAGE_SPEC"
    PACKAGE_BCACHED_DIR="$PACKAGE_WORKING_DIR/src/_"
    PACKAGE_INSTALL_DIR="$NDKPKG_PACKAGE_INSTALLED_ROOT/$TARGET_PLATFORM_SPEC/$PACKAGE_INSTALL_SHA"

    if [ -z "$PACKAGE_BSCRIPT" ] ; then
        PACKAGE_BSCRIPT_DIR="$PACKAGE_WORKING_DIR/src"
    else
        PACKAGE_BSCRIPT_DIR="$PACKAGE_WORKING_DIR/src/$PACKAGE_BSCRIPT"
    fi

    #########################################################################################

    [ "$LOG_LEVEL" -ge "$LOG_LEVEL_VERBOSE" ] && {
        cat <<EOF
PACKAGE_WORKING_DIR = $PACKAGE_WORKING_DIR
PACKAGE_BSCRIPT_DIR = $PACKAGE_BSCRIPT_DIR
PACKAGE_BCACHED_DIR = $PACKAGE_BCACHED_DIR
PACKAGE_INSTALL_DIR = $PACKAGE_INSTALL_DIR
EOF
}

    #########################################################################################

    step "create and change to the working directory"

    run install -d "$PACKAGE_WORKING_DIR"

    run cd "$PACKAGE_WORKING_DIR"

    run install -d src/_ fix res bin lib include map

    #########################################################################################

    PACKAGE_INSTALLING_SRC_DIR="$PACKAGE_WORKING_DIR/src"
    PACKAGE_INSTALLING_FIX_DIR="$PACKAGE_WORKING_DIR/fix"
    PACKAGE_INSTALLING_RES_DIR="$PACKAGE_WORKING_DIR/res"
    PACKAGE_INSTALLING_BIN_DIR="$PACKAGE_WORKING_DIR/bin"
    PACKAGE_INSTALLING_LIB_DIR="$PACKAGE_WORKING_DIR/lib"
    PACKAGE_INSTALLING_INC_DIR="$PACKAGE_WORKING_DIR/include"

    #########################################################################################

    TOOLCHAIN_CONFIG_TARGET="$SESSION_DIR/toolchain-target.sh"

    if [ ! -f "$TOOLCHAIN_CONFIG_TARGET" ] ; then
        println_android_ndk_info > "$TOOLCHAIN_CONFIG_TARGET"
    fi

    #########################################################################################

    TOOLCHAIN_CONFIG_NATIVE="$SESSION_DIR/toolchain-native.sh"

    if [ -f "$TOOLCHAIN_CONFIG_NATIVE" ] ; then
        .   "$TOOLCHAIN_CONFIG_NATIVE"
    else
        case $NATIVE_PLATFORM_KIND in
            darwin)
                step "locate C/C++ toolchain for native build"

                     CC_FOR_BUILD="$(xcrun --sdk macosx --find clang)"
                   OBJC_FOR_BUILD="$(xcrun --sdk macosx --find clang)"
                    CXX_FOR_BUILD="$(xcrun --sdk macosx --find clang++)"
                     AS_FOR_BUILD="$(xcrun --sdk macosx --find as)"
                     AR_FOR_BUILD="$(xcrun --sdk macosx --find ar)"
                 RANLIB_FOR_BUILD="$(xcrun --sdk macosx --find ranlib)"
                     LD_FOR_BUILD="$(xcrun --sdk macosx --find ld)"
                     NM_FOR_BUILD="$(xcrun --sdk macosx --find nm)"
                   SIZE_FOR_BUILD="$(xcrun --sdk macosx --find size)"
                  STRIP_FOR_BUILD="$(xcrun --sdk macosx --find strip)"
                STRINGS_FOR_BUILD="$(xcrun --sdk macosx --find strings)"
                OBJDUMP_FOR_BUILD="$(xcrun --sdk macosx --find objdump)"
                SYSROOT_FOR_BUILD="$(xcrun --sdk macosx --show-sdk-path)"

                CCFLAGS_FOR_BUILD="-isysroot $SYSROOT_FOR_BUILD -mmacosx-version-min=$NATIVE_PLATFORM_VERS -arch $NATIVE_PLATFORM_ARCH -Qunused-arguments"
                LDFLAGS_FOR_BUILD='-Wl,-search_paths_first'
                ;;
            linux)
                step "install C/C++ toolchain for native build"

                if [ -f '/lib/ld-musl-x86_64.so.1' ] && ldd --version 2>&1 | grep -q musl ; then
                    if [ ! -f '/lib64/ld-linux-x86-64.so.2' ] || ! command -v g++ > /dev/null ; then
                        if [ -f /sbin/apk ] && [ -x /sbin/apk ] ; then
                            run $sudo /sbin/apk update
                            run $sudo /sbin/apk add gcompat g++ linux-headers
                        else
                            abort 1 'Due to Android NDK for Linux is linked dynamically against glibc, hence you need to install glibc and g++ by yourself for this system'
                        fi
                    fi

                    CXX_FOR_BUILD="$(command -v g++ || command -v clang++ || command -v c++)" || abort 1 "C++ Compiler for native not found."
                     CC_FOR_BUILD="$(command -v gcc || command -v clang   || command -v cc)"  || abort 1 "C Compiler for native not found."
                   OBJC_FOR_BUILD="$(command -v gcc || command -v clang   || command -v cc)"  || abort 1 "C Compiler for native not found."
                     AS_FOR_BUILD="$(command -v as)"      || abort 1 "command not found: as"
                     AR_FOR_BUILD="$(command -v ar)"      || abort 1 "command not found: ar"
                 RANLIB_FOR_BUILD="$(command -v ranlib)"  || abort 1 "command not found: ranlib"
                     LD_FOR_BUILD="$(command -v ld)"      || abort 1 "command not found: ld"
                     NM_FOR_BUILD="$(command -v nm)"      || abort 1 "command not found: nm"
                   SIZE_FOR_BUILD="$(command -v size)"    || abort 1 "command not found: size"
                  STRIP_FOR_BUILD="$(command -v strip)"   || abort 1 "command not found: strip"
                STRINGS_FOR_BUILD="$(command -v strings)" || abort 1 "command not found: strings"
                OBJDUMP_FOR_BUILD="$(command -v objdump)" || abort 1 "command not found: objdump"
                OBJCOPY_FOR_BUILD="$(command -v objcopy)" || abort 1 "command not found: objcopy"
                READELF_FOR_BUILD="$(command -v readelf)" || abort 1 "command not found: readelf"
                else
                    uppm about
                    uppm update
                    uppm install zig@0.15 binutils

                    export PATH="$UPPM_HOME/installed/binutils/bin:$PATH"
                    export  ZIG="$UPPM_HOME/installed/zig@0.15/bin/zig"

                    CXX_FOR_BUILD="$NDKPKG_CORE_DIR/zig-c++"
                     CC_FOR_BUILD="$NDKPKG_CORE_DIR/zig-cc"
                   OBJC_FOR_BUILD="$NDKPKG_CORE_DIR/zig-cc"
                     AS_FOR_BUILD="$UPPM_HOME/installed/binutils/bin/as"
                     AR_FOR_BUILD="$UPPM_HOME/installed/binutils/bin/ar"
                 RANLIB_FOR_BUILD="$UPPM_HOME/installed/binutils/bin/ranlib"
                     LD_FOR_BUILD="$UPPM_HOME/installed/binutils/bin/ld"
                     NM_FOR_BUILD="$UPPM_HOME/installed/binutils/bin/nm"
                   SIZE_FOR_BUILD="$UPPM_HOME/installed/binutils/bin/size"
                  STRIP_FOR_BUILD="$UPPM_HOME/installed/binutils/bin/strip"
                STRINGS_FOR_BUILD="$UPPM_HOME/installed/binutils/bin/strings"
                OBJDUMP_FOR_BUILD="$UPPM_HOME/installed/binutils/bin/objdump"
                OBJCOPY_FOR_BUILD="$UPPM_HOME/installed/binutils/bin/objcopy"
                READELF_FOR_BUILD="$UPPM_HOME/installed/binutils/bin/readelf"
                fi

                # https://gcc.gnu.org/onlinedocs/gcc/Link-Options.html
                CCFLAGS_FOR_BUILD="-fPIC -fno-common -Doff64_t=off_t"
                LDFLAGS_FOR_BUILD="-Wl,--as-needed"
                ;;
            android)
                step "install C/C++ toolchain for native build"

                run pkg install -y clang binutils

                    CXX_FOR_BUILD="$(command -v g++ || command -v clang++ || command -v c++)" || abort 1 "C++ Compiler for native not found."
                     CC_FOR_BUILD="$(command -v gcc || command -v clang   || command -v cc)"  || abort 1 "C Compiler for native not found."
                   OBJC_FOR_BUILD="$(command -v gcc || command -v clang   || command -v cc)"  || abort 1 "C Compiler for native not found."
                     AS_FOR_BUILD="$(command -v as)"      || abort 1 "command not found: as"
                     AR_FOR_BUILD="$(command -v ar)"      || abort 1 "command not found: ar"
                 RANLIB_FOR_BUILD="$(command -v ranlib)"  || abort 1 "command not found: ranlib"
                     LD_FOR_BUILD="$(command -v ld)"      || abort 1 "command not found: ld"
                     NM_FOR_BUILD="$(command -v nm)"      || abort 1 "command not found: nm"
                   SIZE_FOR_BUILD="$(command -v size)"    || abort 1 "command not found: size"
                  STRIP_FOR_BUILD="$(command -v strip)"   || abort 1 "command not found: strip"
                STRINGS_FOR_BUILD="$(command -v strings)" || abort 1 "command not found: strings"
                OBJDUMP_FOR_BUILD="$(command -v objdump)" || abort 1 "command not found: objdump"
                OBJCOPY_FOR_BUILD="$(command -v objcopy)" || abort 1 "command not found: objcopy"
                READELF_FOR_BUILD="$(command -v readelf)" || abort 1 "command not found: readelf"
        esac

        if [ "$DEBUG_CC" = 1 ] ; then
            CCFLAGS_FOR_BUILD="$CCFLAGS_FOR_BUILD -v"
        fi

        if [ "$DEBUG_LD" = 1 ] ; then
            LDFLAGS_FOR_BUILD="$LDFLAGS_FOR_BUILD -Wl,-v"
        fi

        if [ "$PROFILE" = release ] ; then
            CCFLAGS_FOR_BUILD="$CCFLAGS_FOR_BUILD -Os"
            LDFLAGS_FOR_BUILD="$LDFLAGS_FOR_BUILD -Wl,-S"
        fi

        cat > "$TOOLCHAIN_CONFIG_NATIVE" <<EOF
     CC_FOR_BUILD='$CC_FOR_BUILD'
   OBJC_FOR_BUILD='$OBJC_FOR_BUILD'
    CXX_FOR_BUILD='$CXX_FOR_BUILD'
     AS_FOR_BUILD='$AS_FOR_BUILD'
     AR_FOR_BUILD='$AR_FOR_BUILD'
 RANLIB_FOR_BUILD='$RANLIB_FOR_BUILD'
     LD_FOR_BUILD='$LD_FOR_BUILD'
     NM_FOR_BUILD='$NM_FOR_BUILD'
   SIZE_FOR_BUILD='$SIZE_FOR_BUILD'
  STRIP_FOR_BUILD='$STRIP_FOR_BUILD'
STRINGS_FOR_BUILD='$STRINGS_FOR_BUILD'
OBJDUMP_FOR_BUILD='$OBJDUMP_FOR_BUILD'
OBJCOPY_FOR_BUILD='$OBJCOPY_FOR_BUILD'
READELF_FOR_BUILD='$READELF_FOR_BUILD'
SYSROOT_FOR_BUILD='$SYSROOT_FOR_BUILD'

CCFLAGS_FOR_BUILD='$CCFLAGS_FOR_BUILD'
LDFLAGS_FOR_BUILD='$LDFLAGS_FOR_BUILD'
EOF
    fi

    export PROXIED_CC_FOR_BUILD="$CC_FOR_BUILD"
    export PROXIED_CXX_FOR_BUILD="$CXX_FOR_BUILD"
    export PROXIED_OBJC_FOR_BUILD="$OBJC_FOR_BUILD"

    export CCFLAGS_FOR_BUILD

    CFLAGS_FOR_BUILD="$CCFLAGS_FOR_BUILD"

     CC_FOR_BUILD="$NDKPKG_CORE_DIR/wrapper-native-cc"
   OBJC_FOR_BUILD="$NDKPKG_CORE_DIR/wrapper-native-objc"
    CXX_FOR_BUILD="$NDKPKG_CORE_DIR/wrapper-native-c++"
    CPP_FOR_BUILD="$CC_FOR_BUILD -E"

    #########################################################################################

    for TOOL in CC OBJC CXX CPP AS AR RANLIB LD NM STRIP SIZE STRINGS OBJDUMP OBJCOPY READELF SYSROOT CFLAGS OBJCFLAGS CXXFLAGS CPPFLAGS LDFLAGS
    do
        export "${TOOL}_FOR_BUILD"
        eval export "$TOOL=\"\$${TOOL}_FOR_BUILD\""
    done

    #########################################################################################

    PKG_CONFIG_PATH_FOR_BUILD="$NDKPKG_CORE_DIR/lib/pkgconfig"

    #########################################################################################

    if [ "$PACKAGE_USE_CMAKE" = 1 ] ; then
        # https://cmake.org/cmake/help/latest/manual/cmake-env-variables.7.html#manual:cmake-env-variables(7)

        unset CMAKE_APPBUNDLE_PATH
        unset CMAKE_FRAMEWORK_PATH
        unset CMAKE_PROGRAM_PATH
        unset CMAKE_INCLUDE_PATH
        unset CMAKE_LIBRARY_PATH
        unset CMAKE_PREFIX_PATH
        unset CMAKE_MAXIMUM_RECURSION_DEPTH
        unset CMAKE_APPLE_SILICON_PROCESSOR
        unset CMAKE_BUILD_PARALLEL_LEVEL
        unset CMAKE_BUILD_TYPE
        unset CMAKE_CONFIGURATION_TYPES
        unset CMAKE_CONFIG_TYPE
        unset CMAKE_EXPORT_COMPILE_COMMANDS
        unset CMAKE_GENERATOR
        unset CMAKE_GENERATOR_INSTANCE
        unset CMAKE_GENERATOR_PLATFORM
        unset CMAKE_GENERATOR_TOOLSET
        unset CMAKE_INSTALL_MODE
        unset CMAKE_C_COMPILER_LAUNCHER
        unset CMAKE_C_LINKER_LAUNCHER
        unset CMAKE_CXX_COMPILER_LAUNCHER
        unset CMAKE_CXX_LINKER_LAUNCHER
        unset CMAKE_MSVCIDE_RUN_PATH
        unset CMAKE_NO_VERBOSE
        unset CMAKE_OSX_ARCHITECTURES
        unset CMAKE_TOOLCHAIN_FILE
        unset DESTDIR
        unset VERBOSE
        unset CTEST_INTERACTIVE_DEBUG_MODE
        unset CTEST_OUTPUT_ON_FAILURE
        unset CTEST_PARALLEL_LEVEL
        unset CTEST_PROGRESS_OUTPUT
        unset CTEST_USE_LAUNCHERS_DEFAULT
        unset DASHBOARD_TEST_FROM_CTEST

        # https://cmake.org/cmake/help/latest/envvar/CMAKE_BUILD_PARALLEL_LEVEL.html
        export CMAKE_BUILD_PARALLEL_LEVEL="$BUILD_NJOBS"

        # https://cmake.org/cmake/help/latest/envvar/CMAKE_GENERATOR.html
        if [ "$PACKAGE_USE_NINJA" = 1 ] ; then
            export CMAKE_GENERATOR='Ninja'
        else
            export CMAKE_GENERATOR='Unix Makefiles'
        fi

        # https://cmake.org/cmake/help/latest/envvar/CMAKE_EXPORT_COMPILE_COMMANDS.html
        if [ "$REQUEST_TO_EXPORT_COMPILE_COMMANDS_JSON" = 1 ] ; then
            export CMAKE_EXPORT_COMPILE_COMMANDS=ON
        else
            export CMAKE_EXPORT_COMPILE_COMMANDS=OFF
        fi

        case $PROFILE in
            debug)   CMAKE_BUILD_TYPE=Debug   ;;
            release) CMAKE_BUILD_TYPE=Release ;;
        esac

        if [ "$VERBOSE_CMAKE" = 1 ] ; then
            CMAKE_VERBOSE_MAKEFILE=ON
            CMAKE_COLOR_MAKEFILE=ON
            CMAKE_INSTALL_MESSAGE=ALWAYS
        else
            CMAKE_VERBOSE_MAKEFILE=OFF
            CMAKE_COLOR_MAKEFILE=OFF
            CMAKE_INSTALL_MESSAGE=NEVER
        fi

        # https://cmake.org/cmake/help/latest/variable/CMAKE_FIND_DEBUG_MODE.html
        if [ "$DEBUG_CMAKE" = 1 ] ; then
            CMAKE_FIND_DEBUG_MODE=ON
        else
            CMAKE_FIND_DEBUG_MODE=OFF
        fi
    fi

    #########################################################################################

    unset RECURSIVE_DEPENDENT_PACKAGE_NAMES

    [ -n "$PACKAGE_DEP_PKG" ] && {
        step "calculate dependency list of $1"

        unset PACKAGE_NAME_STACK

        for item in $PACKAGE_DEP_PKG
        do
            if [ -z "$item" ] ; then
                PACKAGE_NAME_STACK="$item"
            else
                PACKAGE_NAME_STACK="$PACKAGE_NAME_STACK;$item"
            fi
        done

        while [ -n "$PACKAGE_NAME_STACK" ]
        do
            case $PACKAGE_NAME_STACK in
                *\;*) TOPE="${PACKAGE_NAME_STACK##*;}" ; PACKAGE_NAME_STACK="${PACKAGE_NAME_STACK%;*}" ;;
                *)    TOPE="${PACKAGE_NAME_STACK}"     ; PACKAGE_NAME_STACK=
            esac

            RECURSIVE_DEPENDENT_PACKAGE_NAMES2="$TOPE"

            for item in $RECURSIVE_DEPENDENT_PACKAGE_NAMES
            do
                if [ "$item" != "$TOPE" ] ; then
                    RECURSIVE_DEPENDENT_PACKAGE_NAMES2="$RECURSIVE_DEPENDENT_PACKAGE_NAMES2 $item"
                fi
            done

            RECURSIVE_DEPENDENT_PACKAGE_NAMES="$RECURSIVE_DEPENDENT_PACKAGE_NAMES2"

            unset TOPE_UPPERCASE_UNDERSCORE
            TOPE_UPPERCASE_UNDERSCORE=$(printf '%s\n' "$TOPE" | tr '@+-.' '_' | tr a-z A-Z)

            for item in $(eval echo \$PACKAGE_DEP_PKG_"${TOPE_UPPERCASE_UNDERSCORE}")
            do
                if [ -z "$item" ] ; then
                    PACKAGE_NAME_STACK="$item"
                else
                    PACKAGE_NAME_STACK="$PACKAGE_NAME_STACK;$item"
                fi
            done
        done

        printf '%s\n' "$RECURSIVE_DEPENDENT_PACKAGE_NAMES"
    }

    #########################################################################################

    unset RECURSIVE_DEPENDENT_PACKAGE_INSTALL_DIRS

    [ -n "$PACKAGE_DEP_PKG" ] && {
        for DEPENDENT_PACKAGE_NAME in $RECURSIVE_DEPENDENT_PACKAGE_NAMES
        do
            DEPENDENT_PACKAGE_INSTALL_DIR="$NDKPKG_PACKAGE_INSTALLED_ROOT/$TARGET_PLATFORM_SPEC/$DEPENDENT_PACKAGE_NAME"

            if [ -z "$RECURSIVE_DEPENDENT_PACKAGE_INSTALL_DIRS" ] ; then
                RECURSIVE_DEPENDENT_PACKAGE_INSTALL_DIRS="$DEPENDENT_PACKAGE_INSTALL_DIR"
            else
                RECURSIVE_DEPENDENT_PACKAGE_INSTALL_DIRS="$RECURSIVE_DEPENDENT_PACKAGE_INSTALL_DIRS $DEPENDENT_PACKAGE_INSTALL_DIR"
            fi

            #########################################################################################

            DEPENDENT_PACKAGE_BINARY__DIR="$NATIVE_PACKAGE_INSTALLED_ROOT/$DEPENDENT_PACKAGE_NAME/bin"

            if [ -d  "$DEPENDENT_PACKAGE_BINARY__DIR" ] ; then
                PATH="$DEPENDENT_PACKAGE_BINARY__DIR:$PATH"
            fi

            DEPENDENT_PACKAGE_BINARY__DIR="$NATIVE_PACKAGE_INSTALLED_ROOT/$DEPENDENT_PACKAGE_NAME/sbin"

            if [ -d  "$DEPENDENT_PACKAGE_BINARY__DIR" ] ; then
                PATH="$DEPENDENT_PACKAGE_BINARY__DIR:$PATH"
            fi

            if [ -d          "$NATIVE_PACKAGE_INSTALLED_ROOT/$DEPENDENT_PACKAGE_NAME/share/aclocal" ] ; then
                ACLOCAL_PATH="$NATIVE_PACKAGE_INSTALLED_ROOT/$DEPENDENT_PACKAGE_NAME/share/aclocal:$ACLOCAL_PATH"
            fi
        done
    }

    #########################################################################################

    [ -n "$PACKAGE_DEP_PKG" ] && {
        step "generate  dependency tree of $1"

        unset DOT_CONTENT
        unset D2__CONTENT

        STACK="$PACKAGE_NAME"

        while [ -n "$STACK" ]
        do
            case $STACK in
                *\;*) TOPE="${STACK##*;}" ; STACK="${STACK%;*}" ;;
                *)    TOPE="${STACK}"     ; STACK=
            esac

            unset TOPE_UPPERCASE_UNDERSCORE
            TOPE_UPPERCASE_UNDERSCORE=$(printf '%s\n' "$TOPE" | tr '@+-.' '_' | tr a-z A-Z)

            TOPE_DEP_PKG="$(eval echo \$PACKAGE_DEP_PKG_"${TOPE_UPPERCASE_UNDERSCORE}")"

            [ -z "$TOPE_DEP_PKG" ] && continue

            DOUBLE_QUOTE_LIST=

            for item in $TOPE_DEP_PKG
            do
                if [ "$item" = "$TOPE" ] ; then
                    abort 1 "package '$TOPE' depends itself."
                fi

                D2__CONTENT="$D2__CONTENT
$TOPE -> $item"

                DOUBLE_QUOTE_LIST="$DOUBLE_QUOTE_LIST \"$item\""

                if [ -z "$STACK" ] ; then
                    STACK="$item"
                else
                    STACK="$STACK;$item"
                fi
            done

            DOT_CONTENT="$DOT_CONTENT
\"$TOPE\" -> {$DOUBLE_QUOTE_LIST }"
        done

        DOT_CONTENT="digraph G {
$DOT_CONTENT
}"

        ##################################################

        PACKAGE_DEPENDENCY_GRAPH_FILEPATH_D2_="$PACKAGE_WORKING_DIR/dependencies.d2"
        PACKAGE_DEPENDENCY_GRAPH_FILEPATH_DOT="$PACKAGE_WORKING_DIR/dependencies.dot"
        PACKAGE_DEPENDENCY_GRAPH_FILEPATH_BOX="$PACKAGE_WORKING_DIR/dependencies.box"

        ##################################################

        printf '%s\n' "$D2__CONTENT" > "$PACKAGE_DEPENDENCY_GRAPH_FILEPATH_D2_"
        printf '%s\n' "$DOT_CONTENT" > "$PACKAGE_DEPENDENCY_GRAPH_FILEPATH_DOT"

        ##################################################

        # https://github.com/ggerganov/dot-to-ascii
        curl \
            -o "$PACKAGE_DEPENDENCY_GRAPH_FILEPATH_BOX" \
            -s \
            -G \
            --data-urlencode "boxart=1" \
            --data-urlencode "src=$DOT_CONTENT" \
            "https://dot-to-ascii.ggerganov.com/dot-to-ascii.php" || true

        ##################################################

        DOT="$(command -v dot || command -v dot_static || true)"

        if [ -n "$DOT" ] ; then
            run "$DOT" -Tsvg -o "$PACKAGE_WORKING_DIR/dependencies.svg" "$PACKAGE_DEPENDENCY_GRAPH_FILEPATH_DOT" || true
        else
            D2="$(command -v d2 || true)"

            if [ -n "$D2" ] ; then
                run "$D2" "$PACKAGE_DEPENDENCY_GRAPH_FILEPATH_D2_" "$PACKAGE_WORKING_DIR/dependencies.svg"
            fi
        fi

        ##################################################

        if [ -f "$PACKAGE_DEPENDENCY_GRAPH_FILEPATH_BOX" ] ; then
            cat "$PACKAGE_DEPENDENCY_GRAPH_FILEPATH_BOX"
        else
            cat "$PACKAGE_DEPENDENCY_GRAPH_FILEPATH_DOT"
        fi
    }

    #########################################################################################

    if [ "$PACKAGE_USE_GMAKE" = 1 ] && [ "$REQUEST_TO_EXPORT_COMPILE_COMMANDS_JSON" = 1 ] && [ "$BEAR_ENABLED" = 1 ] ; then
        PACKAGE_DEP_UPP="$PACKAGE_DEP_UPP bear"
    fi

    if [ "$ENABLE_CCACHE" = 1 ] ; then
        PACKAGE_DEP_UPP="$PACKAGE_DEP_UPP ccache"
    fi

    #########################################################################################

    unset PACKAGE_USE_PERL
    unset PACKAGE_USE_PYTHON3
    unset PACKAGE_USE_GOLANG

    unset PACKAGE_AUX_LIBZ
    unset PACKAGE_AUX_LIBOPENSSL

    # these native packages would be built from source locally due to they are not relocatable or libraries
    unset PACKAGE_AUX_NEED_TO_BUILD_LOCALLY

    PACKAGE_DEP_AUX="$PACKAGE_DEP_UPP"
    PACKAGE_DEP_UPP=

    for UPPM_PACKAGE_NAME in $PACKAGE_DEP_AUX
    do
        case $UPPM_PACKAGE_NAME in
            libz)
                PACKAGE_AUX_LIBZ=1
                PACKAGE_AUX_NEED_TO_BUILD_LOCALLY="$PACKAGE_AUX_NEED_TO_BUILD_LOCALLY libz"
                ;;
            libopenssl)
                PACKAGE_AUX_LIBOPENSSL=1
                PACKAGE_AUX_NEED_TO_BUILD_LOCALLY="$PACKAGE_AUX_NEED_TO_BUILD_LOCALLY libopenssl"
                ;;
            automake)
                PACKAGE_AUX_NEED_TO_BUILD_LOCALLY="$PACKAGE_AUX_NEED_TO_BUILD_LOCALLY autoconf automake"
                PACKAGE_DEP_UPP="$PACKAGE_DEP_UPP gmake gm4"
                PACKAGE_USE_PERL=1
                ;;
            autoconf|libtool|texinfo|help2man|intltool)
                PACKAGE_AUX_NEED_TO_BUILD_LOCALLY="$PACKAGE_AUX_NEED_TO_BUILD_LOCALLY $UPPM_PACKAGE_NAME"
                PACKAGE_DEP_UPP="$PACKAGE_DEP_UPP gmake gm4"
                PACKAGE_USE_PERL=1
                ;;
            itstool)
                PACKAGE_AUX_NEED_TO_BUILD_LOCALLY="$PACKAGE_AUX_NEED_TO_BUILD_LOCALLY itstool"
                PACKAGE_DEP_UPP="$PACKAGE_DEP_UPP gmake gm4"
                PACKAGE_USE_PERL=1
                PACKAGE_USE_PYTHON3=1
                ;;
            perl)
                PACKAGE_USE_PERL=1
                ;;
            python3)
                PACKAGE_USE_PYTHON3=1
                ;;
            golang)
                PACKAGE_USE_GOLANG=1
                ;;
            depot_tools)
                PACKAGE_USE_PYTHON3=1
                PACKAGE_DEP_UPP="$PACKAGE_DEP_UPP gn ninja"

                run git clone --depth=1 https://chromium.googlesource.com/chromium/tools/depot_tools.git
                export PATH="$PACKAGE_WORKING_DIR/depot_tools:$PATH"
                export DEPOT_TOOLS_UPDATE=0
                ;;
            *)  PACKAGE_DEP_UPP="$PACKAGE_DEP_UPP $UPPM_PACKAGE_NAME"
        esac
    done

    #########################################################################################

    if [ "$TERMUX" = 1 ] ; then
        unset TERMUX_PKGS

        [ "$PACKAGE_USE_PERL"    = 1 ] && TERMUX_PKGS="$TERMUX_PKGS perl"
        [ "$PACKAGE_USE_PYTHON3" = 1 ] && TERMUX_PKGS="$TERMUX_PKGS python"
        [ "$PACKAGE_USE_GOLANG"  = 1 ] && TERMUX_PKGS="$TERMUX_PKGS golang"
        [ "$PACKAGE_USE_CARGO"   = 1 ] && TERMUX_PKGS="$TERMUX_PKGS rust"

        if [ -n "$TERMUX_PKGS" ] ; then
            step "install needed packages via pkg"
            run pkg install -y $TERMUX_PKGS
        fi
    else
        [ "$PACKAGE_USE_PERL"    = 1 ] && PACKAGE_DEP_UPP="$PACKAGE_DEP_UPP perl"
        [ "$PACKAGE_USE_PYTHON3" = 1 ] && PACKAGE_DEP_UPP="$PACKAGE_DEP_UPP python3"
        [ "$PACKAGE_USE_GOLANG"  = 1 ] && PACKAGE_DEP_UPP="$PACKAGE_DEP_UPP golang"
    fi

    #########################################################################################

    step "install needed packages via uppm"

    uppm about
    uppm update

    for UPPM_PACKAGE_NAME in $PACKAGE_DEP_UPP pkg-config patchelf tree
    do
        uppm install "$UPPM_PACKAGE_NAME" $UPPM_INSTALL_ARGS

        UPPM_PACKAGE_INSTALLED_DIR="$UPPM_HOME/installed/$UPPM_PACKAGE_NAME"

        if [ -d  "$UPPM_PACKAGE_INSTALLED_DIR/bin" ] ; then
            PATH="$UPPM_PACKAGE_INSTALLED_DIR/bin:$PATH"
        fi

        if [ -d  "$UPPM_PACKAGE_INSTALLED_DIR/sbin" ] ; then
            PATH="$UPPM_PACKAGE_INSTALLED_DIR/sbin:$PATH"
        fi

        if [ -d          "$UPPM_PACKAGE_INSTALLED_DIR/share/aclocal" ] ; then
            ACLOCAL_PATH="$UPPM_PACKAGE_INSTALLED_DIR/share/aclocal:$ACLOCAL_PATH"
        fi

        case $UPPM_PACKAGE_NAME in
            swig)
                # https://www.swig.org/Doc4.0/Library.html
                X="$(ls $UPPM_PACKAGE_INSTALLED_DIR/share/swig/*/swig.swg)"
                export SWIG_LIB="${X%/*}"
                ;;
            file)
                export MAGIC="$UPPM_PACKAGE_INSTALLED_DIR/share/misc/magic.mgc"
                ;;
            docbook-xsl)
                # http://xmlsoft.org/xslt/xsltproc.html
                export XML_CATALOG_FILES="$UPPM_PACKAGE_INSTALLED_DIR/catalog.xml"
                printf '%s\n' "XML_CATALOG_FILES=$XML_CATALOG_FILES"
        esac
    done

    #########################################################################################

    for NATIVE_PACKAGE_NAME in $PACKAGE_AUX_NEED_TO_BUILD_LOCALLY
    do
        (install_the_given_native_package "$NATIVE_PACKAGE_NAME")

        NATIVE_PACKAGE_INSTALLED_DIR="$NATIVE_PACKAGE_INSTALLED_ROOT/$NATIVE_PACKAGE_NAME"

        if [ -d  "$NATIVE_PACKAGE_INSTALLED_DIR/include" ] ; then
            CPPFLAGS_FOR_BUILD="$CPPFLAGS_FOR_BUILD -I$NATIVE_PACKAGE_INSTALLED_DIR/include"
        fi

        if [ -d  "$NATIVE_PACKAGE_INSTALLED_DIR/lib" ] ; then
            LDFLAGS_FOR_BUILD="$LDFLAGS_FOR_BUILD -L$NATIVE_PACKAGE_INSTALLED_DIR/lib -Wl,-rpath,$NATIVE_PACKAGE_INSTALLED_DIR/lib"
        fi

        if [ -d  "$NATIVE_PACKAGE_INSTALLED_DIR/bin" ] ; then
            PATH="$NATIVE_PACKAGE_INSTALLED_DIR/bin:$PATH"
        fi

        if [ -d  "$NATIVE_PACKAGE_INSTALLED_DIR/sbin" ] ; then
            PATH="$NATIVE_PACKAGE_INSTALLED_DIR/sbin:$PATH"
        fi

        if [ -d          "$NATIVE_PACKAGE_INSTALLED_DIR/share/aclocal" ] ; then
            ACLOCAL_PATH="$NATIVE_PACKAGE_INSTALLED_DIR/share/aclocal:$ACLOCAL_PATH"
        fi

        for d in lib share
        do
            NATIVE_PACKAGE_PKGCONF_DIR="$NATIVE_PACKAGE_INSTALLED_DIR/$d/pkgconfig"

            if [ -d "$NATIVE_PACKAGE_PKGCONF_DIR" ] ; then
                PKG_CONFIG_PATH_FOR_BUILD="$PKG_CONFIG_PATH_FOR_BUILD:$NATIVE_PACKAGE_PKGCONF_DIR"
                break
            fi
        done
    done

    #########################################################################################

    [ -n "$PACKAGE_DEP_PIP" ] && {
        step "install needed python packages via pip"

        PYTHON3="$(command -v python3)" || abort 1 "command not found: python3"

        run "$PYTHON3" --version
        run "$PYTHON3" -m pip install --upgrade pip
        run "$PYTHON3" -m pip install --upgrade "$PACKAGE_DEP_PIP"
    }

    #########################################################################################

    [ -n "$PACKAGE_DEP_PLM" ] && {
        step "install needed perl modules via cpan"

        unset PACKAGE_DEP_PLM_T1
        unset PACKAGE_DEP_PLM_T2

        for item in $PACKAGE_DEP_PLM
        do
            if [ "$item" = 'XML::Parser' ] ; then
                PACKAGE_DEP_PLM_T1='XML::Parser'
            else
                PACKAGE_DEP_PLM_T2="$PACKAGE_DEP_PLM_T2 $item"
            fi
        done

        if [ -n "$PACKAGE_DEP_PLM_T1" ] ; then
            (install_the_given_native_package perl_XML_Parser)
        fi

        if [ -n "$PACKAGE_DEP_PLM_T2" ] ; then
            PACKAGE_DEP_PLM_T2="${PACKAGE_DEP_PLM_T2# }"
        fi

        if [ -n "$PACKAGE_DEP_PLM_T2" ] ; then
            # Would you like to configure as much as possible automatically? [yes]
            # https://perldoc.perl.org/cpan#PERL_MM_USE_DEFAULT
            export PERL_MM_USE_DEFAULT=1
            run cpan "$PACKAGE_DEP_PLM_T2"
        fi

        if [ -d "$HOME/perl5/bin" ] ; then
            # cpan install to default local location
            bppend_to_PATH "$HOME/perl5/bin"
        fi
    }

    #########################################################################################

    [ "$PACKAGE_USE_CARGO" = 1 ] && [ "$TERMUX" != 1 ] && {
        command -v rustup > /dev/null || {
            # https://www.rust-lang.org/tools/install
            note "${COLOR_GREEN}rustup cargo rustc${COLOR_OFF} ${COLOR_YELLOW}commands are required, but it was not found, let's install it.${COLOR_OFF}"

            wfetch 'https://sh.rustup.rs' -o rustup-init.sh --no-buffer

            run bash rustup-init.sh -y
        }
    }

    #########################################################################################

    step "locate needed tools"

    unset AUTORECONF
    unset AUTOCONF
    unset AUTOMAKE
    unset ACLOCAL
    unset PERL
    unset M4

    unset MESON
    unset CMAKE
    unset XMAKE
    unset GMAKE
    unset NINJA

    unset BEAR
    unset CCACHE
    unset PKG_CONFIG

    if [ "$PACKAGE_USE_AUTOGENSH" = 1 ] || [ "$PACKAGE_USE_AUTOTOOLS" = 1 ] ; then
        AUTORECONF=$(command -v autoreconf) || abort 1 "command not found: autoreconf"
        AUTOCONF=$(command -v autoconf)     || abort 1 "command not found: autoconf"
        AUTOMAKE=$(command -v automake)     || abort 1 "command not found: automake"
        ACLOCAL=$(command -v aclocal)       || abort 1 "command not found: aclocal"
        PERL=$(command -v perl)             || abort 1 "command not found: perl"
        M4=$(command -v m4)                 || abort 1 "command not found: m4"
    fi

    [ "$PACKAGE_USE_MESON" = 1 ] && {
        MESON=$(command -v meson) || abort 1 "command not found: meson"
    }

    [ "$PACKAGE_USE_CMAKE" = 1 ] && {
        CMAKE=$(command -v cmake) || abort 1 "command not found: cmake"
    }

    [ "$PACKAGE_USE_XMAKE" = 1 ] && {
        XMAKE=$(command -v xmake) || abort 1 "command not found: xmake"

        # error: Running xmake as root is extremely dangerous and no longer supported.
        # As xmake does not drop privileges on installation you would be giving all
        # build scripts full access to your system.
        # Or you can add `--root` option or XMAKE_ROOT=y to allow run as root temporarily.
        export XMAKE_ROOT=y
    }

    [ "$PACKAGE_USE_GMAKE" = 1 ] && {
        GMAKE=$(command -v gmake || command -v make) || abort 1 "command not found: gmake and make"
    }

    [ "$PACKAGE_USE_NINJA" = 1 ] && {
        NINJA=$(command -v ninja) || abort 1 "command not found: ninja"
    }

    [ "$PACKAGE_USE_CARGO" = 1 ] && {
        [ "$TERMUX" = 1 ] ||
        RUSTUP=$(command -v rustup) || abort 1 "command not found: rustup"

        CARGO=$(command -v cargo)   || abort 1 "command not found: cargo"
    }

    [ "$PACKAGE_USE_GO" = 1 ] && {
        GO=$(command -v go) || abort 1 "command not found: go"
    }

    [ "$ENABLE_CCACHE" = 1 ] && {
        CCACHE=$(command -v ccache) || abort 1 "command not found: ccache"
    }

    PKG_CONFIG=$(command -v pkg-config || command -v pkgconf) || abort 1 "command not found: pkg-config"

    unset  M4
    export M4="$(command -v m4 || true)"

    PATCHELF=$(command -v patchelf) || abort 1 "command not found: patchelf"

    TREE=$(command -v tree) || abort 1 "command not found: tree"

    #########################################################################################

    step "dofetch"

    if [ -n "$PACKAGE_DOFETCH" ] ; then
        eval "
dofetch() {
$PACKAGE_DOFETCH
}"
        dofetch
    else
        case $PACKAGE_SRC_URL in
            '')
                if [ -n "$PACKAGE_GIT_URL" ] ; then
                    unset GIT_FETCH_URL

                    if [ -z "$NDKPKG_URL_TRANSFORM" ] ; then
                        GIT_FETCH_URL="$PACKAGE_GIT_URL"
                    else
                        GIT_FETCH_URL="$("$NDKPKG_URL_TRANSFORM" "$PACKAGE_GIT_URL")" || return 1
                    fi

                    if [ -z "$PACKAGE_GIT_SHA" ] ; then
                        if [ -z "$PACKAGE_GIT_REF" ] ; then
                            GIT_BRANCH_NAME=master
                            GIT_REF_SPEC="+HEAD:refs/remotes/origin/master"
                        else
                            GIT_BRANCH_NAME="$(basename "$PACKAGE_GIT_REF")"
                            GIT_REF_SPEC="+$PACKAGE_GIT_REF:refs/remotes/origin/$GIT_BRANCH_NAME"
                        fi
                    else
                        GIT_BRANCH_NAME=master
                        GIT_REF_SPEC="+$PACKAGE_GIT_SHA:refs/remotes/origin/master"
                    fi

                    if [ -z "$PACKAGE_GIT_NTH" ] ; then
                        PACKAGE_GIT_NTH=1
                    fi

                    if [ "$PACKAGE_GIT_NTH" -eq 0 ] ; then
                        if [ -f "$PACKAGE_SRC_FILEPATH/.git/shallow" ] ; then
                            GIT_FETCH_EXTRA_OPTIONS='--unshallow'
                        else
                            GIT_FETCH_EXTRA_OPTIONS=
                        fi
                    else
                        GIT_FETCH_EXTRA_OPTIONS="--depth=$PACKAGE_GIT_NTH"
                    fi

                    run cd "$PACKAGE_INSTALLING_SRC_DIR"

                    run git -c init.defaultBranch=master init
                    run git remote add origin "$GIT_FETCH_URL"
                    run git -c protocol.version=2 fetch --progress $GIT_FETCH_EXTRA_OPTIONS origin "$GIT_REF_SPEC"
                    run git checkout --progress --force -B "$GIT_BRANCH_NAME" "refs/remotes/origin/$GIT_BRANCH_NAME"

                    git_submodule_update_recursive
                fi
                ;;
            dir://*)
                note "$PACKAGE_SRC_URL is local path, no need to fetch."
                ;;
            file://*)
                note "$PACKAGE_SRC_URL is local path, no need to fetch."
                ;;
            *)  wfetch "$PACKAGE_SRC_URL" --uri="$PACKAGE_SRC_URI" --sha256="$PACKAGE_SRC_SHA" -o "$PACKAGE_SRC_FILEPATH"
        esac

        if [ -n    "$PACKAGE_FIX_URL" ] ; then
            wfetch "$PACKAGE_FIX_URL" --uri="$PACKAGE_FIX_URI" --sha256="$PACKAGE_FIX_SHA" -o "$PACKAGE_FIX_FILEPATH"
        fi

        if [ -n    "$PACKAGE_RES_URL" ] ; then
            wfetch "$PACKAGE_RES_URL" --uri="$PACKAGE_RES_URI" --sha256="$PACKAGE_RES_SHA" -o "$PACKAGE_RES_FILEPATH"
        fi

        #########################################################################################

        step "unpack/copy resources to proper location"

        if [ -n "$PACKAGE_SRC_FILEPATH" ] ; then
            case $PACKAGE_SRC_FILETYPE in
                .dir)
                    if [ -d "$PACKAGE_SRC_FILEPATH" ] ; then
                        if [ -d "$PACKAGE_SRC_FILEPATH/.git" ] && command -v git > /dev/null ; then
                            PACKAGE_GIT_SHA=$(git -C "$PACKAGE_SRC_FILEPATH" rev-parse HEAD || true)
                        fi
                        run cp -r "$PACKAGE_SRC_FILEPATH/." "$PACKAGE_INSTALLING_SRC_DIR"
                    else
                        abort 1 "src-url point to dir '$PACKAGE_SRC_FILEPATH' does not exist."
                    fi
                    ;;
                .git)
                    if [ -z "$PACKAGE_GIT_SHA" ] ; then
                        PACKAGE_GIT_SHA="$(git rev-parse HEAD)"
                    fi
                    ;;
                .zip|.txz|.tgz|.tlz|.tbz2|.crate)
                    run bsdtar xf "$PACKAGE_SRC_FILEPATH" -C "$PACKAGE_INSTALLING_SRC_DIR" --strip-components 1 --no-same-owner
                    ;;
                *)  run cp "$PACKAGE_SRC_FILEPATH" "$PACKAGE_INSTALLING_SRC_DIR/"
            esac
        fi

        if [ -n "$PACKAGE_FIX_FILEPATH" ] ; then
            case $PACKAGE_FIX_FILETYPE in
                .zip|.txz|.tgz|.tlz|.tbz2|.crate)
                    run bsdtar xf "$PACKAGE_FIX_FILEPATH" -C "$PACKAGE_INSTALLING_FIX_DIR" --strip-components 1 --no-same-owner
                    ;;
                *)  run cp "$PACKAGE_FIX_FILEPATH" "$PACKAGE_INSTALLING_FIX_DIR/"
                    printf '%s|%s\n' "$PACKAGE_FIX_FILENAME" "$PACKAGE_FIX_OPT" > "$PACKAGE_INSTALLING_FIX_DIR/index"
            esac
        fi

        if [ -n "$PACKAGE_RES_FILEPATH" ] ; then
            case $PACKAGE_RES_FILETYPE in
                .zip|.txz|.tgz|.tlz|.tbz2|.crate)
                    run bsdtar xf "$PACKAGE_RES_FILEPATH" -C "$PACKAGE_INSTALLING_RES_DIR" --strip-components 1 --no-same-owner
                    ;;
                *)  run cp "$PACKAGE_RES_FILEPATH" "$PACKAGE_INSTALLING_RES_DIR/"
            esac
        fi

        [ -n "$PACKAGE_PATCHES" ] && {
            printf '%s\n' "$PACKAGE_PATCHES" | while read -r LINE
            do
                SHA="$(printf '%s\n' "$LINE" | cut -d '|' -f1)"
                URL="$(printf '%s\n' "$LINE" | cut -d '|' -f2)"
                URI="$(printf '%s\n' "$LINE" | cut -d '|' -f3)"
                OPT="$(printf '%s\n' "$LINE" | cut -d '|' -f4)"

                FILETYPE="$(filetype_from_url "$URL")"
                FILENAME="$SHA$FILETYPE"
                FILEPATH="$NDKPKG_DOWNLOADS_DIR/$FILENAME"

                wfetch "$URL" --uri="$URI" --sha256="$SHA" -o "$FILEPATH"

                case $FILETYPE in
                    .zip|.txz|.tgz|.tlz|.tbz2|.crate)
                        run bsdtar xf "$FILEPATH" -C "$PACKAGE_INSTALLING_FIX_DIR" --strip-components 1 --no-same-owner
                        ;;
                    *)  run cp "$FILEPATH" "$PACKAGE_INSTALLING_FIX_DIR/"
                        printf '%s|%s\n' "$FILENAME" "$OPT" >> "$PACKAGE_INSTALLING_FIX_DIR/index"
                esac
            done
        }

        [ -n "$PACKAGE_RESLIST" ] && {
            printf '%s\n' "$PACKAGE_RESLIST" | while read -r LINE
            do
                SHA="$(printf '%s\n' "$LINE" | cut -d '|' -f1)"
                URL="$(printf '%s\n' "$LINE" | cut -d '|' -f2)"
                URI="$(printf '%s\n' "$LINE" | cut -d '|' -f3)"
                DIR="$(printf '%s\n' "$LINE" | cut -d '|' -f4)"
                LEV="$(printf '%s\n' "$LINE" | cut -d '|' -f5)"

                [ -z "$LEV" ] && LEV=1

                FILETYPE="$(filetype_from_url "$URL")"
                FILENAME="$SHA$FILETYPE"
                FILEPATH="$NDKPKG_DOWNLOADS_DIR/$FILENAME"

                wfetch "$URL" --uri="$URI" --sha256="$SHA" -o "$FILEPATH"

                if [ -z "$DIR" ] ; then
                    DEST="$PACKAGE_INSTALLING_RES_DIR"
                else
                    DEST="$PACKAGE_INSTALLING_RES_DIR/$DIR"
                    run install -d "$DEST"
                fi

                case $FILETYPE in
                    .zip|.txz|.tgz|.tlz|.tbz2|.crate)
                        run bsdtar xf "$FILEPATH" -C "$DEST" --strip-components "$LEV" --no-same-owner
                        ;;
                    *)  run cp "$FILEPATH" "$DEST/"
                esac
            done
        }
    fi

    #########################################################################################

    [ "$LOG_LEVEL" -ge "$LOG_LEVEL_VERBOSE" ] && {
        step "tree files of the installing top directory"
        run tree --dirsfirst -L 2 "$PACKAGE_WORKING_DIR"

        step "list files of the installing src directory"
        run ls -l "$PACKAGE_INSTALLING_SRC_DIR"

        if [ -n "$PACKAGE_BSCRIPT" ] ; then
            step "list files of the installing build script directory"
            run ls -l "$PACKAGE_BSCRIPT_DIR"
        fi
    }

    #########################################################################################

    step "change to the build script directory"
    run cd "$PACKAGE_BSCRIPT_DIR"

    #########################################################################################

    {
        [ "$PACKAGE_USE_AUTOGENSH" = 1 ] ||
        [ "$PACKAGE_USE_AUTOTOOLS" = 1 ] ||
        [ "$PACKAGE_USE_CONFIGURE" = 1 ]
    } && {
        step "update config.{sub,guess}"
        __update_config_sub_guess
    }

    #########################################################################################

    if [ -n "$PACKAGE_DO12345" ] ; then
        step "install for native"

        NATIVE_BUILD_NEEDED=1

        NATIVE_INSTALLED_VERSION_TXT_FILEPATH="$NATIVE_PACKAGE_INSTALLED_ROOT/$PACKAGE_NAME/version.txt"

        [ -f "$NATIVE_INSTALLED_VERSION_TXT_FILEPATH" ] && {
            if [ "$(cat "$NATIVE_INSTALLED_VERSION_TXT_FILEPATH")" = "$PACKAGE_VERSION" ] ; then
                NATIVE_BUILD_NEEDED=0
                note "install for native already have been done, skipped."
            else
                note "install for native already have been done, but not the same version, rebuild it."
            fi
        }

        if [ "$NATIVE_BUILD_NEEDED" = 1 ] ; then
            NATIVE_BCACHED_DIR="$PACKAGE_WORKING_DIR/src/-"
            NATIVE_INSTALL_DIR="$NATIVE_PACKAGE_INSTALLED_ROOT/$PACKAGE_INSTALL_SHA"

            cat <<EOF
NATIVE_BCACHED_DIR = $NATIVE_BCACHED_DIR
NATIVE_INSTALL_DIR = $NATIVE_INSTALL_DIR
EOF

            (
                PACKAGE_BCACHED_DIR="$NATIVE_BCACHED_DIR"
                PACKAGE_INSTALL_DIR="$NATIVE_INSTALL_DIR"

                run install -d "$PACKAGE_BCACHED_DIR"

                if [ "$PACKAGE_BINBSTD" = 1 ] ; then
                    run cd "$PACKAGE_BSCRIPT_DIR"
                else
                    run cd "$PACKAGE_BCACHED_DIR"
                fi

                [ "$DUMP_ENV" = 1 ] && {
                    run export -p
                    echo
                }

                eval "
build_for_native() {
$PACKAGE_DO12345
}"

                BUILD_FOR_NATIVE=1

                build_for_native
            )

            [ -d "$NATIVE_INSTALL_DIR" ] && {
                printf '%s\n' "$PACKAGE_VERSION" > "$NATIVE_INSTALL_DIR/version.txt"
                run ln -s -r -f -T "$NATIVE_INSTALL_DIR" "$NATIVE_PACKAGE_INSTALLED_ROOT/$PACKAGE_NAME"
            }
        else
            NATIVE_INSTALL_DIR="$NATIVE_PACKAGE_INSTALLED_ROOT/$PACKAGE_NAME"
        fi

        [ -d "$NATIVE_INSTALL_DIR" ] && {
            if [ -d  "$NATIVE_INSTALL_DIR/bin" ] ; then
                PATH="$NATIVE_INSTALL_DIR/bin:$PATH"
            fi

            if [ -d  "$NATIVE_INSTALL_DIR/sbin" ] ; then
                PATH="$NATIVE_INSTALL_DIR/sbin:$PATH"
            fi

            if [ -d          "$NATIVE_INSTALL_DIR/share/aclocal" ] ; then
                ACLOCAL_PATH="$NATIVE_INSTALL_DIR/share/aclocal:$ACLOCAL_PATH"
            fi
        }
    fi

    #########################################################################################
    #                            below is for target                                        #
    #########################################################################################

    if [ "$TARGET_PLATFORM_ARCH" = armv7a ] ; then
        TARGET_TRIPLE='armv7a-linux-androideabi'
    else
        TARGET_TRIPLE="$TARGET_PLATFORM_ARCH-linux-android"
    fi

    export ANDROID_NDK_COMPILER_ARGS="--target=${TARGET_TRIPLE}${TARGET_PLATFORM_VERS} --sysroot=$ANDROID_NDK_SYSROOT -Qunused-arguments"

    export ANDROID_NDK_CC
    export ANDROID_NDK_CXX

    #########################################################################################

    export      CC="$NDKPKG_CORE_DIR/wrapper-target-cc"
    export     CXX="$NDKPKG_CORE_DIR/wrapper-target-c++"
    export     CPP="$CC -E"
    export      LD="$ANDROID_NDK_LD"
    export      AS="$ANDROID_NDK_AS"
    export      AR="$ANDROID_NDK_AR"
    export      NM="$ANDROID_NDK_NM"
    export    SIZE="$ANDROID_NDK_SIZE"
    export   STRIP="$ANDROID_NDK_STRIP"
    export  RANLIB="$ANDROID_NDK_RANLIB"
    export STRINGS="$ANDROID_NDK_STRINGS"
    export OBJDUMP="$ANDROID_NDK_OBJDUMP"
    export OBJCOPY="$ANDROID_NDK_OBJCOPY"
    export READELF="$ANDROID_NDK_READELF"
    export SYSROOT="$ANDROID_NDK_SYSROOT"

    #########################################################################################

    NDKPKG_COMMON_H_FILEPATH="$PACKAGE_INSTALLING_INC_DIR/ndk-pkg-common.h"

    #########################################################################################

    # https://gcc.gnu.org/onlinedocs/gcc-4.3.6/gcc/Warning-Options.html
    CCFLAGS='-fPIC -Wall'
    XXFLAGS='-fPIC -Wall'
    PPFLAGS="-include $NDKPKG_COMMON_H_FILEPATH"
    LDFLAGS='-Wl,--as-needed -Wl,-z,muldefs -Wl,--allow-multiple-definition'

    CCFLAGS="$CCFLAGS $PACKAGE_CCFLAGS"
    XXFLAGS="$XXFLAGS $PACKAGE_XXFLAGS"
    PPFLAGS="$PPFLAGS $PACKAGE_PPFLAGS"

    for FLAG in $PACKAGE_LDFLAGS
    do
        case $FLAG in
            --static|-static) ;;
            *)  LDFLAGS="$LDFLAGS $FLAG"
        esac
    done

    ##############################################

    _F_COMMON_OPT_IS_SET=0

    for item in $PACKAGE_CCFLAGS
    do
        [ "$item" = '-fcommon' ] && {
            _F_COMMON_OPT_IS_SET=1
            break
        }
    done

    if [ "$_F_COMMON_OPT_IS_SET" = 0 ] ; then
        CCFLAGS="$CCFLAGS -fno-common"
    fi

    ##############################################

    _F_COMMON_OPT_IS_SET=0

    for item in $PACKAGE_XXFLAGS
    do
        [ "$item" = '-fcommon' ] && {
            _F_COMMON_OPT_IS_SET=1
            break
        }
    done

    if [ "$_F_COMMON_OPT_IS_SET" = 0 ] ; then
        XXFLAGS="$XXFLAGS -fno-common"
    fi

    ##############################################

    if [ "$PACKAGE_CREATE_FULLY_STATICALLY_LINKED_EXECUTABLE" = 1 ] ; then
        LDFLAGS="-static --static -ffunction-sections -fdata-sections -Wl,--gc-sections -Wl,--no-dynamic-linker $LDFLAGS"
    fi

    if [ "$PACKAGE_CREATE_MOSTLY_STATICALLY_LINKED_EXECUTABLE" = 1 ] ; then
        LDFLAGS="-static-libstdc++ $LDFLAGS"
    fi

    ##############################################

    if [ "$DEBUG_CC" = 1 ] ; then
        CCFLAGS="$CCFLAGS -v"
        XXFLAGS="$XXFLAGS -v"
    fi

    if [ "$DEBUG_LD" = 1 ] ; then
        LDFLAGS="$LDFLAGS -Wl,-v"
    fi

    ##############################################

    case $PROFILE in
        debug)
            CCFLAGS="$CCFLAGS -O0 -g"
            XXFLAGS="$XXFLAGS -O0 -g"
            ;;
        release)
            CCFLAGS="$CCFLAGS -Os"
            XXFLAGS="$XXFLAGS -Os"

            unset _U_NDEBUG_OPT_IS_SET

            for item in $PACKAGE_PPFLAGS
            do
                [ "$item" = '-UNDEBUG' ] && {
                    _U_NDEBUG_OPT_IS_SET=1
                    break
                }
            done

            if [ "$_U_NDEBUG_OPT_IS_SET" != 1 ] ; then
                PPFLAGS="$PPFLAGS -DNDEBUG"
            fi

            if [ -z "$ENABLE_LTO" ] || [ "$ENABLE_LTO" = 1 ] ; then
                LDFLAGS="$LDFLAGS -flto"
            fi

            case $ENABLE_STRIP in
                all)   LDFLAGS="$LDFLAGS -Wl,-s" ;;
                debug) LDFLAGS="$LDFLAGS -Wl,-S" ;;
            esac
    esac

    ##############################################

    for DEPENDENT_PACKAGE_NAME in $RECURSIVE_DEPENDENT_PACKAGE_NAMES
    do
        DEPENDENT_PACKAGE_NAME_UNDERSCORE=$(printf '%s\n' "$DEPENDENT_PACKAGE_NAME" | tr '@+-.' '_')

        DEPENDENT_PACKAGE_INSTALL_DIR="$NDKPKG_PACKAGE_INSTALLED_ROOT/$TARGET_PLATFORM_SPEC/$DEPENDENT_PACKAGE_NAME"
        DEPENDENT_PACKAGE_INCLUDE_DIR="$DEPENDENT_PACKAGE_INSTALL_DIR/include"
        DEPENDENT_PACKAGE_LIBRARY_DIR="$DEPENDENT_PACKAGE_INSTALL_DIR/lib"
        DEPENDENT_PACKAGE_PKGCONF_DIR="$DEPENDENT_PACKAGE_INSTALL_DIR/lib/pkgconfig"

        eval "${DEPENDENT_PACKAGE_NAME_UNDERSCORE}_INSTALL_DIR='$DEPENDENT_PACKAGE_INSTALL_DIR'"
        eval "${DEPENDENT_PACKAGE_NAME_UNDERSCORE}_INCLUDE_DIR='$DEPENDENT_PACKAGE_INCLUDE_DIR'"
        eval "${DEPENDENT_PACKAGE_NAME_UNDERSCORE}_LIBRARY_DIR='$DEPENDENT_PACKAGE_LIBRARY_DIR'"

        if [ -d "$DEPENDENT_PACKAGE_INCLUDE_DIR" ] ; then
            PPFLAGS="-I$DEPENDENT_PACKAGE_INCLUDE_DIR $PPFLAGS"
        fi

        if [ -d "$DEPENDENT_PACKAGE_LIBRARY_DIR" ] ; then
            LDFLAGS="-L$DEPENDENT_PACKAGE_LIBRARY_DIR -Wl,-rpath-link,$DEPENDENT_PACKAGE_LIBRARY_DIR $LDFLAGS"
        fi
    done

    PPFLAGS="-I$PACKAGE_INSTALLING_INC_DIR $PPFLAGS"
    LDFLAGS="-L$PACKAGE_INSTALLING_LIB_DIR $LDFLAGS"

    for DEPENDENT_PACKAGE_NAME in $PACKAGE_DEP_PKG
    do
        # https://android.googlesource.com/platform/bionic/+/master/docs/status.md

        case $DEPENDENT_PACKAGE_NAME in
            libexecinfo)
                if [ "$TARGET_PLATFORM_VERS" -lt 33 ] ; then
                    # https://android.googlesource.com/platform/bionic/+/master/libc/include/execinfo.h
                    # https://android.googlesource.com/platform/bionic/+/master/libc/bionic/execinfo.cpp
                    PPFLAGS="$PPFLAGS -include $libexecinfo_INCLUDE_DIR/execinfo.h"
                    LDFLAGS="$LDFLAGS -l:libexecinfo.a -lm"
                fi
                ;;
            libgetloadavg)
                if [ "$TARGET_PLATFORM_VERS" -lt 29 ] ; then
                    # https://android.googlesource.com/platform/bionic/+/master/libc/include/stdlib.h#157
                    # https://android.googlesource.com/platform/bionic/+/master/libc/bionic/getloadavg.cpp
                    # int getloadavg(double __averages[], int __n) __INTRODUCED_IN(29);
                    PPFLAGS="$PPFLAGS -include $libgetloadavg_INCLUDE_DIR/getloadavg.h"
                    LDFLAGS="$LDFLAGS -l:libgetloadavg.a"
                fi
                ;;
            libposix_spawn)
                if [ "$TARGET_PLATFORM_VERS" -lt 28 ] ; then
                    PPFLAGS="$PPFLAGS -include $libposix_spawn_INCLUDE_DIR/posix_spawn.h"
                    LDFLAGS="$LDFLAGS -l:libposix_spawn.a -lc++"
                fi
                ;;
            libglob)
                # https://pubs.opengroup.org/onlinepubs/9699919799/functions/glob.html
                # https://android.googlesource.com/platform/bionic/+/master/libc/include/glob.h
                if [ "$TARGET_PLATFORM_VERS" -lt 28 ] ; then
                    LDFLAGS="$LDFLAGS -l:libglob.a"
                fi
                ;;
            liblanginfo)
                # https://pubs.opengroup.org/onlinepubs/9699919799/functions/nl_langinfo.html
                # https://android.googlesource.com/platform/bionic/+/master/libc/include/langinfo.h
                if [ "$TARGET_PLATFORM_VERS" -lt 26 ] ; then
                    LDFLAGS="$LDFLAGS -l:liblanginfo.a"
                fi
                ;;
            libmblen)
                # https://android.googlesource.com/platform/bionic/+/master/libc/include/stdlib.h#163
                # https://android.googlesource.com/platform/bionic/+/master/libc/bionic/mblen.cpp
                # int mblen(const char* __s, size_t __n) __INTRODUCED_IN_NO_GUARD_FOR_NDK(26);
                if [ "$TARGET_PLATFORM_VERS" -lt 26 ] ; then
                    PPFLAGS="$PPFLAGS -include $libmblen_INCLUDE_DIR/mblen.h"
                    LDFLAGS="$LDFLAGS -l:libmblen.a"
                fi
                ;;
            libgetdomainname)
                # https://android.googlesource.com/platform/bionic/+/master/libc/include/unistd.h#313
                # https://android.googlesource.com/platform/bionic/+/master/libc/bionic/getdomainname.cpp
                # int getdomainname(char* __buf, size_t __buf_size) __INTRODUCED_IN(26);
                if [ "$TARGET_PLATFORM_VERS" -lt 26 ] ; then
                    PPFLAGS="$PPFLAGS -include $libgetdomainname_INCLUDE_DIR/getdomainname.h"
                    LDFLAGS="$LDFLAGS -l:libgetdomainname.a"
                fi
                ;;
            libstrchrnul)
                # https://android.googlesource.com/platform/bionic/+/master/libc/include/string.h#68
                # char* strchrnul(char* __s, int __ch) __RENAME(strchrnul) __attribute_pure__ __INTRODUCED_IN(24);
                if [ "$TARGET_PLATFORM_VERS" -lt 24 ] ; then
                    PPFLAGS="$PPFLAGS -include $libstrchrnul_INCLUDE_DIR/strchrnul.h"
                    LDFLAGS="$LDFLAGS -l:libstrchrnul.a"
                fi
                ;;
            libgetdtablesize)
                # https://android.googlesource.com/platform/bionic/+/72dc1c22dc6a92dea925398c9e3880364ab29c1c/libc/bionic/getdtablesize.c
                PPFLAGS="$PPFLAGS -include $libgetdtablesize_INCLUDE_DIR/getdtablesize.h"
                LDFLAGS="$LDFLAGS -l:libgetdtablesize.a"
                ;;
        esac
    done

    export   CFLAGS="$CCFLAGS"
    export CXXFLAGS="$XXFLAGS"
    export CPPFLAGS="$PPFLAGS"
    export  LDFLAGS="$LDFLAGS"

    #########################################################################################

    # https://specifications.freedesktop.org/basedir-spec/basedir-spec-latest.html
    export XDG_DATA_DIRS

    for DEPENDENT_PACKAGE_INSTALL_DIR in $RECURSIVE_DEPENDENT_PACKAGE_INSTALL_DIRS
    do
        # https://gi.readthedocs.io/en/latest/tools/g-ir-scanner.html#environment-variables
        if [ -d "$DEPENDENT_PACKAGE_INSTALL_DIR/share/gir-1.0" ] ; then
            if [ -z "$XDG_DATA_DIRS" ] ; then
                XDG_DATA_DIRS="$DEPENDENT_PACKAGE_INSTALL_DIR/share"
            else
                XDG_DATA_DIRS="$DEPENDENT_PACKAGE_INSTALL_DIR/share:$XDG_DATA_DIRS"
            fi
        fi

        # https://help.gnome.org/admin//system-admin-guide/2.32/mimetypes-database.html.en
        if [ -d "$DEPENDENT_PACKAGE_INSTALL_DIR/share/mime" ] ; then
            if [ -z "$XDG_DATA_DIRS" ] ; then
                XDG_DATA_DIRS="$DEPENDENT_PACKAGE_INSTALL_DIR/share"
            else
                XDG_DATA_DIRS="$DEPENDENT_PACKAGE_INSTALL_DIR/share:$XDG_DATA_DIRS"
            fi
        fi
    done

    #########################################################################################

    # https://www.gnu.org/software/automake/manual/html_node/Macro-Search-Path.html
    export ACLOCAL_PATH

    for DEPENDENT_PACKAGE_INSTALL_DIR in $RECURSIVE_DEPENDENT_PACKAGE_INSTALL_DIRS
    do
        DEPENDENT_PACKAGE_ACLOCAL_PATH="$DEPENDENT_PACKAGE_INSTALL_DIR/share/aclocal"

        if [ -d "$DEPENDENT_PACKAGE_ACLOCAL_PATH" ] ; then
            if [ -z "$ACLOCAL_PATH" ] ; then
                ACLOCAL_PATH="$DEPENDENT_PACKAGE_ACLOCAL_PATH"
            else
                ACLOCAL_PATH="$DEPENDENT_PACKAGE_ACLOCAL_PATH:$ACLOCAL_PATH"
            fi
        fi
    done

    #########################################################################################

    PATH="$PACKAGE_INSTALLING_BIN_DIR:$ANDROID_NDK_HOME:$PATH"

    #########################################################################################

    # override the default search directory (usually /usr/lib/pkgconfig:/usr/share/pkgconfig)
    # because we only want to use our own
    export PKG_CONFIG_LIBDIR="$PACKAGE_WORKING_DIR/lib/pkgconfig"
    export PKG_CONFIG_PATH="$PACKAGE_WORKING_DIR/lib/pkgconfig"

    for DEPENDENT_PACKAGE_INSTALL_DIR in $RECURSIVE_DEPENDENT_PACKAGE_INSTALL_DIRS
    do
        for d in lib share
        do
            DEPENDENT_PACKAGE_PKGCONF_DIR="$DEPENDENT_PACKAGE_INSTALL_DIR/$d/pkgconfig"

            if [ -d "$DEPENDENT_PACKAGE_PKGCONF_DIR" ] ; then
                PKG_CONFIG_PATH="$PKG_CONFIG_PATH:$DEPENDENT_PACKAGE_PKGCONF_DIR"
            fi
        done
    done

    #########################################################################################

    for item in $PACKAGE_DEP_LIB
    do
        case $item in
            -l*);;
            *)  item="$(pkg-config --libs-only-l "$item")"
        esac

        ANDROID_NDK_COMPILER_ARGS="$ANDROID_NDK_COMPILER_ARGS $item"
    done

    #########################################################################################

    if [ "$PACKAGE_USE_CMAKE" = 1 ] ; then
        # https://cmake.org/cmake/help/latest/manual/cmake-env-variables.7.html#manual:cmake-env-variables(7)

        unset CMAKE_PREFIX_PATH
        unset CMAKE_APPLE_SILICON_PROCESSOR
        unset CMAKE_BUILD_PARALLEL_LEVEL
        unset CMAKE_BUILD_TYPE
        unset CMAKE_CONFIGURATION_TYPES
        unset CMAKE_CONFIG_TYPE
        unset CMAKE_EXPORT_COMPILE_COMMANDS
        unset CMAKE_GENERATOR
        unset CMAKE_GENERATOR_INSTANCE
        unset CMAKE_GENERATOR_PLATFORM
        unset CMAKE_GENERATOR_TOOLSET
        unset CMAKE_INSTALL_MODE
        unset CMAKE_C_COMPILER_LAUNCHER
        unset CMAKE_C_LINKER_LAUNCHER
        unset CMAKE_CXX_COMPILER_LAUNCHER
        unset CMAKE_CXX_LINKER_LAUNCHER
        unset CMAKE_MSVCIDE_RUN_PATH
        unset CMAKE_NO_VERBOSE
        unset CMAKE_OSX_ARCHITECTURES
        unset CMAKE_TOOLCHAIN_FILE
        unset DESTDIR
        unset CTEST_INTERACTIVE_DEBUG_MODE
        unset CTEST_OUTPUT_ON_FAILURE
        unset CTEST_PARALLEL_LEVEL
        unset CTEST_PROGRESS_OUTPUT
        unset CTEST_USE_LAUNCHERS_DEFAULT
        unset DASHBOARD_TEST_FROM_CTEST

        # https://cmake.org/cmake/help/latest/envvar/CMAKE_BUILD_PARALLEL_LEVEL.html
        export CMAKE_BUILD_PARALLEL_LEVEL="$BUILD_NJOBS"

        # https://cmake.org/cmake/help/latest/envvar/CMAKE_GENERATOR.html
        if [ "$PACKAGE_USE_NINJA" = 1 ] ; then
            export CMAKE_GENERATOR='Ninja'
        else
            export CMAKE_GENERATOR='Unix Makefiles'
        fi

        # https://cmake.org/cmake/help/latest/envvar/CMAKE_EXPORT_COMPILE_COMMANDS.html
        if [ "$REQUEST_TO_EXPORT_COMPILE_COMMANDS_JSON" = 1 ] ; then
            export CMAKE_EXPORT_COMPILE_COMMANDS=ON
        else
            export CMAKE_EXPORT_COMPILE_COMMANDS=OFF
        fi

        case $PROFILE in
            debug)   CMAKE_BUILD_TYPE=Debug   ;;
            release) CMAKE_BUILD_TYPE=Release ;;
        esac

        if [ "$VERBOSE_CMAKE" = 1 ] ; then
            CMAKE_VERBOSE_MAKEFILE=ON
            CMAKE_COLOR_MAKEFILE=ON
            CMAKE_INSTALL_MESSAGE=ALWAYS
        else
            CMAKE_VERBOSE_MAKEFILE=OFF
            CMAKE_COLOR_MAKEFILE=OFF
            CMAKE_INSTALL_MESSAGE=NEVER
        fi

        # https://cmake.org/cmake/help/latest/variable/CMAKE_FIND_DEBUG_MODE.html
        if [ "$DEBUG_CMAKE" = 1 ] ; then
            CMAKE_FIND_DEBUG_MODE=ON
        else
            CMAKE_FIND_DEBUG_MODE=OFF
        fi

        # https://cmake.org/cmake/help/latest/variable/CMAKE_FIND_ROOT_PATH.html
        unset CMAKE_FIND_ROOT_PATH

        if [ -n "$PACKAGE_DEP_PKG" ] ; then
            CMAKE_FIND_ROOT_PATH="$(printf '%s\n' "$RECURSIVE_DEPENDENT_PACKAGE_INSTALL_DIRS" | tr ' ' ';')"
        fi
    fi

    #########################################################################################

    if [ "$PACKAGE_USE_CARGO" = 1 ] ; then
        # https://docs.rs/backtrace/latest/backtrace/
        export RUST_BACKTRACE=1

        export CARGO_BUILD_JOBS="$BUILD_NJOBS"

        #########################################################################

        RUST_TARGET_FOR_BUILD="$(rustc -vV | sed -n '/host: /p' | cut -c7- | tr 'a-z-' 'A-Z_')"

        # https://doc.rust-lang.org/cargo/reference/config.html#environment-variables
        # https://doc.rust-lang.org/cargo/reference/environment-variables.html
        export "CARGO_TARGET_${RUST_TARGET_FOR_BUILD}_AR"="$AR_FOR_BUILD"
        export "CARGO_TARGET_${RUST_TARGET_FOR_BUILD}_LINKER"="$CC_FOR_BUILD"

        # https://doc.rust-lang.org/rustc/codegen-options/index.html#link-arg
        RUSTFLAGS_FOR_BUILD="-Clinker=$CC_FOR_BUILD"

        for LDARG in $LDFLAGS_FOR_BUILD
        do
            RUSTFLAGS_FOR_BUILD="$RUSTFLAGS_FOR_BUILD -Clink-arg=$LDARG"
        done

        [ "$PACKAGE_AUX_LIBZ" = 1 ] && {
            RUSTFLAGS_FOR_BUILD="$RUSTFLAGS_FOR_BUILD -L native=$NATIVE_PACKAGE_INSTALLED_ROOT/libz"
        }

        export "CARGO_TARGET_${RUST_TARGET_FOR_BUILD}_RUSTFLAGS"="$RUSTFLAGS_FOR_BUILD"

        #########################################################################

        # https://libraries.io/cargo/pkg-config
        # https://crates.io/crates/pkg-config
        # https://docs.rs/pkg-config/latest/pkg_config/
        # https://github.com/rust-lang/pkg-config-rs
        export HOST_PKG_CONFIG_PATH="$PKG_CONFIG_PATH_FOR_BUILD"
        export HOST_PKG_CONFIG_LIBDIR="$NDKPKG_CORE_DIR/lib/pkgconfig"

        #########################################################################

        # https://libraries.io/cargo/cc
        # https://crates.io/crates/cc
        # https://docs.rs/cc/latest/cc/
        # https://github.com/alexcrichton/cc-rs
        export HOST_CC="$CC_FOR_BUILD"
        export HOST_CFLAGS="$CFLAGS_FOR_BUILD $CPPFLAGS_FOR_BUILD $LDFLAGS_FOR_BUILD"

        export HOST_CXX="$CXX_FOR_BUILD"
        export HOST_CXXFLAGS="$CXXFLAGS_FOR_BUILD $CPPFLAGS_FOR_BUILD $LDFLAGS_FOR_BUILD"

        export HOST_AR="$AR_FOR_BUILD"

        #########################################################################

        RUST_TARGET_FOR_BUILD_UNDERSCORE="$(rustc -vV | sed -n '/host: /p' | cut -c7- | tr '-' '_')"

        eval unset "AR_${RUST_TARGET_FOR_BUILD_UNDERSCORE}"
        eval unset "CC_${RUST_TARGET_FOR_BUILD_UNDERSCORE}"
        eval unset "CFLAGS_${RUST_TARGET_FOR_BUILD_UNDERSCORE}"
        eval unset "CXX_${RUST_TARGET_FOR_BUILD_UNDERSCORE}"
        eval unset "CXXFLAGS_${RUST_TARGET_FOR_BUILD_UNDERSCORE}"

        #########################################################################

        # https://docs.rs/openssl/latest/openssl/
        [ "$PACKAGE_AUX_LIBOPENSSL" = 1 ] && {
            eval export "${RUST_TARGET_FOR_BUILD}_OPENSSL_DIR='$NATIVE_PACKAGE_INSTALLED_ROOT/libopenssl'"
            eval export "${RUST_TARGET_FOR_BUILD}_OPENSSL_NO_VENDOR=1"
            export OPENSSL_NO_VENDOR=1
        }

        #########################################################################

        # this environment variable is not defined by Rust, but it is widely used by third-party project.
        case $TARGET_PLATFORM_ARCH in
            armv7a)  export RUST_TARGET='armv7-linux-androideabi' ;;
            aarch64) export RUST_TARGET='aarch64-linux-android'   ;;
            i686)    export RUST_TARGET='i686-linux-android'      ;;
            x86_64)  export RUST_TARGET='x86_64-linux-android'    ;;
        esac

        RUST_TARGET_UPPERCASE_UNDERSCORE=$(printf '%s\n' "$RUST_TARGET" | tr a-z A-Z | tr - _)

        # https://doc.rust-lang.org/cargo/reference/config.html#environment-variables
        # https://doc.rust-lang.org/cargo/reference/environment-variables.html
        export "CARGO_TARGET_${RUST_TARGET_UPPERCASE_UNDERSCORE}_AR"="$AR"
        export "CARGO_TARGET_${RUST_TARGET_UPPERCASE_UNDERSCORE}_LINKER"="$CC"

        #########################################################################

        # https://doc.rust-lang.org/rustc/codegen-options/index.html#link-arg
        # https://doc.rust-lang.org/rustc/command-line-arguments.html#-l-add-a-directory-to-the-library-search-path
        export RUSTFLAGS="-Clinker=$CC -L native=$PACKAGE_INSTALLING_LIB_DIR"

        for LDFLAG in $LDFLAGS
        do
            RUSTFLAGS="$RUSTFLAGS -Clink-arg=$LDFLAG"
        done

        #if [ "$TARGET_PLATFORM_ARCH" = x86_64 ] || [ "$TARGET_PLATFORM_ARCH" = i686 ] ; then
            LIBCLANG_RT_BUILTINS_FILEPATH="$("$CC" -print-libgcc-file-name)"
            RUSTFLAGS="$RUSTFLAGS -Clink-arg=$LIBCLANG_RT_BUILTINS_FILEPATH"
        #fi

        #########################################################################

        for DEPENDENT_PACKAGE_NAME in $RECURSIVE_DEPENDENT_PACKAGE_NAMES
        do
            case $DEPENDENT_PACKAGE_NAME in
                openssl@1.1)
                    # https://docs.rs/openssl/latest/openssl/
                    export OPENSSL_DIR="$openssl_1_1_INSTALL_DIR"

                    if [ "$PACKAGE_PKGTYPE" = exe ] ; then
                        # https://github.com/sfackler/rust-openssl/blob/master/openssl-sys/build/main.rs
                        export OPENSSL_STATIC=1
                        export OPENSSL_NO_VENDOR=1
                    fi
                    ;;
                openssl-dev)
                    # https://docs.rs/openssl/latest/openssl/
                    export OPENSSL_DIR="$openssl_dev_INSTALL_DIR"

                    if [ "$PACKAGE_PKGTYPE" = exe ] ; then
                        # https://github.com/sfackler/rust-openssl/blob/master/openssl-sys/build/main.rs
                        export OPENSSL_STATIC=1
                        export OPENSSL_NO_VENDOR=1
                    fi
                    ;;
                libssh2)
                    if [ "$PACKAGE_PKGTYPE" = exe ] ; then
                        # https://github.com/alexcrichton/ssh2-rs/blob/master/libssh2-sys/build.rs
                        export LIBSSH2_SYS_USE_PKG_CONFIG=1
                    fi
                    ;;
                libgit2)
                    if [ "$PACKAGE_PKGTYPE" = exe ] ; then
                        # https://github.com/rust-lang/git2-rs/blob/master/libgit2-sys/build.rs
                        export LIBGIT2_NO_VENDOR=1
                        export LIBGIT2_SYS_USE_PKG_CONFIG=1
                    fi
                    ;;
                libz|zlib)
                    if [ "$PACKAGE_PKGTYPE" = exe ] ; then
                        # https://github.com/rust-lang/libz-sys/blob/main/build.rs
                        export LIBZ_SYS_STATIC=1
                    fi
                    ;;
            esac
        done

        #########################################################################

        # https://libraries.io/cargo/cc
        # https://crates.io/crates/cc
        # https://docs.rs/cc/latest/cc/
        # https://github.com/alexcrichton/cc-rs
        export TARGET_CC="$CC"
        export TARGET_CFLAGS="$CFLAGS $CPPFLAGS $LDFLAGS"

        export TARGET_CXX="$CXX"
        export TARGET_CXXFLAGS="$CXXFLAGS $CPPFLAGS $LDFLAGS"

        export TARGET_AR="$AR"

        #########################################################################

        # https://libraries.io/cargo/pkg-config
        # https://crates.io/crates/pkg-config
        # https://docs.rs/pkg-config/latest/pkg_config/
        # https://github.com/rust-lang/pkg-config-rs
        export TARGET_PKG_CONFIG_ALLOW_CROSS=1

        unset PKG_CONFIG_SYSROOT_DIR

        #########################################################################

        # https://libraries.io/cargo/cmake
        # https://crates.io/crates/cmake
        # https://docs.rs/cmake/latest/cmake/
        # https://github.com/alexcrichton/cmake-rs
        # this variable is not motioned in their document. you must read the source code of cmake-rs crate.
        export TARGET_CMAKE_TOOLCHAIN_FILE="$PACKAGE_WORKING_DIR/android.toolchain.cmake"

        cat > "$TARGET_CMAKE_TOOLCHAIN_FILE" <<EOF
set(ANDROID_ABI "${TARGET_PLATFORM_ABI}")
set(ANDROID_PLATFORM "android-${TARGET_PLATFORM_VERS}")
include(${ANDROID_NDK_HOME}/build/cmake/android.toolchain.cmake)

set(CMAKE_C_COMPILER "$CC")
set(CMAKE_C_FLAGS "$CPPFLAGS $CFLAGS")

set(CMAKE_CXX_COMPILER "$CXX")
set(CMAKE_CXX_FLAGS "$CPPFLAGS $CXXFLAGS")

set(CMAKE_ASM_COMPILER "$CC")

set(CMAKE_SHARED_LINKER_FLAGS "$LDFLAGS")
set(CMAKE_EXE_LINKER_FLAGS    "$LDFLAGS")

set(CMAKE_C_COMPILER_AR     "$AR")
set(CMAKE_C_COMPILER_RANLIB "$RANLIB")

set(CMAKE_CXX_COMPILER_AR     "$AR")
set(CMAKE_CXX_COMPILER_RANLIB "$RANLIB")

set(CMAKE_AR      "$AR")
set(CMAKE_RANLIB  "$RANLIB")

set(CMAKE_LINKER  "$LD")

set(CMAKE_NM      "$NM")
set(CMAKE_READELF "$READELF")

set(CMAKE_OBJCOPY "$OBJCOPY")
set(CMAKE_OBJDUMP "$OBJDUMP")

set(CMAKE_STRIP   "$STRIP")

set(CMAKE_ADDR2LINE "$ADDR2LINE")
EOF
    fi

    #########################################################################################

    if [ "$PACKAGE_USE_GO" = 1 ] ; then
        # https://pkg.go.dev/cmd/cgo
        export CGO_ENABLED=1
        export CGO_CFLAGS="$CFLAGS"
        export CGO_CXXFLAGS="$CXXFLAGS"
        export CGO_CPPFLAGS="$CPPFLAGS"
        export CGO_LDFLAGS="$LDFLAGS"

        # https://go.dev/blog/go116-module-changes
        export GO111MODULE='auto'

        if [ "$COUNTRY" = china ] ; then
            export GOPROXY='https://goproxy.cn'
        fi

        # https://golang.org/doc/install/source#environment
        export GOOS='android'

        case $TARGET_PLATFORM_ARCH in
            armv7a)  export GOARCH=arm   ;;
            aarch64) export GOARCH=arm64 ;;
            i686)    export GOARCH=386   ;;
            x86_64)  export GOARCH=amd64 ;;
        esac
    fi

    #########################################################################################

    # https://pubs.opengroup.org/onlinepubs/000095399/functions/rindex.html
    # https://pubs.opengroup.org/onlinepubs/000095399/functions/bcmp.html
    # https://linux.die.net/man/2/wait3
    # https://stackoverflow.com/questions/32826175/ftello-and-fseeko-android-build-errors
    # https://linux.die.net/man/3/ftello
    # int   fseeko(FILE* __fp, off_t __offset, int __whence) __RENAME(fseeko64) __INTRODUCED_IN(24);
    # off_t ftello(FILE* __fp) __RENAME(ftello64) __INTRODUCED_IN(24);

    cat > "$NDKPKG_COMMON_H_FILEPATH" <<EOF
#ifndef NDKPKG_COMMON_H
#define NDKPKG_COMMON_H

//#define rindex(a,b) strrchr((a),(b))

#define bcmp(b1,b2,len) memcmp((b1), (b2), (size_t)(len))

#define wait3(status,options,rusage) waitpid(-1,status,options)

#if __ANDROID_API__ < 24
    #define ftello(f) ftell(f)
    #define fseeko    fseek
#endif

#endif
EOF

    #########################################################################################

    # https://developer.android.com/ndk/guides/stable_apis#c_library
    # Note that on Android, unlike Linux, there are no separate libpthread or librt libraries.
    # That functionality is included directly in libc, which does not need to be explicitly linked against.
    printf '!<arch>\n' > "$PACKAGE_WORKING_DIR/lib/libpthread.a"
    printf '!<arch>\n' > "$PACKAGE_WORKING_DIR/lib/librt.a"

    if [ "$PACKAGE_CREATE_FULLY_STATICALLY_LINKED_EXECUTABLE" = 1 ] ; then
        printf '!<arch>\n' > "$PACKAGE_WORKING_DIR/lib/liblog.a"
    fi

    if [ "$ANDROID_NDK_VERSION_MAJOR" -ge 23 ] ; then
        # https://github.com/rust-windowing/android-ndk-rs/issues/149
        if [ "$TARGET_PLATFORM_ARCH" = 'x86_64' ] ; then
            LIBCLANG_RT_BUILTINS_FILEPATH="$("$CC" -print-libgcc-file-name)"
        else
            LIBCLANG_RT_BUILTINS_FILEPATH=
        fi

        printf 'INPUT(%s -l:libunwind.a)\n' "$LIBCLANG_RT_BUILTINS_FILEPATH" > "$PACKAGE_WORKING_DIR/lib/libgcc.a"
    fi

    #########################################################################################

    [ -n "$RECURSIVE_DEPENDENT_PACKAGE_NAMES" ] && {
        if [ "$PACKAGE_CREATE_FULLY_STATICALLY_LINKED_EXECUTABLE" = 1 ] || [ "$PACKAGE_CREATE_MOSTLY_STATICALLY_LINKED_EXECUTABLE" = 1 ] ; then
            step "copy dependent libraries to linker first search dir"

            for DEPENDENT_PACKAGE_INSTALL_DIR in $RECURSIVE_DEPENDENT_PACKAGE_INSTALL_DIRS
            do
                DEPENDENT_PACKAGE_LIBRARY_DIR="$DEPENDENT_PACKAGE_INSTALL_DIR/lib"

                if [  -d "$DEPENDENT_PACKAGE_LIBRARY_DIR" ] ; then
                    find "$DEPENDENT_PACKAGE_LIBRARY_DIR" -maxdepth 1 -mindepth 1 -name 'lib*.a' -exec cp -L -v '{}' "$PACKAGE_WORKING_DIR/lib/" \;
                fi
            done
        fi
    }

    #########################################################################################

    [ "$ENABLE_CCACHE" = 1 ] && {
        step "setup ccache"

        run ln -sf "$CCACHE" "$PACKAGE_WORKING_DIR/bin/wrapper-target-cc"
        run ln -sf "$CCACHE" "$PACKAGE_WORKING_DIR/bin/wrapper-target-c++"

        ccache -s > "$PACKAGE_WORKING_DIR/ccache-s.txt"
    }

    #########################################################################################

    step "dopatch for target"

    [ -f "$PACKAGE_INSTALLING_FIX_DIR/index" ] && {
        cd "$PACKAGE_BSCRIPT_DIR"

        while read -r LINE
        do
            FILE="$(printf '%s\n' "$LINE" | cut -d '|' -f1)"
            OPTS="$(printf '%s\n' "$LINE" | cut -d '|' -f2)"
            [ -z "$OPTS" ] && OPTS='-p1'
            run "patch $OPTS < $PACKAGE_INSTALLING_FIX_DIR/$FILE"
        done < "$PACKAGE_INSTALLING_FIX_DIR/index"
    }

    [ -n "$PACKAGE_DOPATCH" ] && {
        cd "$PACKAGE_BSCRIPT_DIR"

        eval "
dopatch() {
$PACKAGE_DOPATCH
}"
        dopatch
    }

    #########################################################################################

    cd "$PACKAGE_BSCRIPT_DIR"

    #########################################################################################

    # https://github.com/golang/go/issues/65568
    [ -f go.mod ] && gsed -i 's|^go 1.22$|go 1.22.0|' go.mod

    #########################################################################################

    case $PACKAGE_BSYSTEM_MASTER in
        autogen)
            if [ -f configure ] ; then
                CONFIGURE_FILE_LAST_MODIFIED_TIMESTAMP="$(stat --format=%Y configure)"

                if [ -z "$CONFIGURE_FILE_LAST_MODIFIED_TIMESTAMP" ] ; then
                    run NOCONFIGURE=yes ./autogen.sh
                elif [ "$CONFIGURE_FILE_LAST_MODIFIED_TIMESTAMP" -lt "$TIMESTAMP_UNIX" ] ; then
                    run NOCONFIGURE=yes ./autogen.sh
                fi
            else
                run NOCONFIGURE=yes ./autogen.sh
            fi
            ;;
        autotools)
            if [ -f configure ] ; then
                CONFIGURE_FILE_LAST_MODIFIED_TIMESTAMP="$(stat --format=%Y configure)"

                if [ -z "$CONFIGURE_FILE_LAST_MODIFIED_TIMESTAMP" ] ; then
                    run autoreconf -ivf
                elif [ "$CONFIGURE_FILE_LAST_MODIFIED_TIMESTAMP" -lt "$TIMESTAMP_UNIX" ] ; then
                    run autoreconf -ivf
                fi
            else
                run autoreconf -ivf
            fi
            ;;
    esac

    #########################################################################################

    [ -n "$PACKAGE_PREPARE" ] && {
        step "prepare for target"

        eval "
prepare() {
$PACKAGE_PREPARE
}"
        prepare
    }

    #########################################################################################

    step "install for target"

    if [ "$PACKAGE_BINBSTD" = 1 ] ; then
        run cd "$PACKAGE_BSCRIPT_DIR"
    else
        run cd "$PACKAGE_BCACHED_DIR"
    fi

    if [        -d "$PACKAGE_INSTALL_DIR" ] ; then
        run rm -rf "$PACKAGE_INSTALL_DIR"
    fi

    [ "$DUMP_ENV" = 1 ] && {
        run export -p
        echo
    }

    eval "
dobuild() {
$PACKAGE_DOBUILD
}"

    dobuild

    #########################################################################################

    [   -d "$PACKAGE_INSTALL_DIR" ] || abort 1 "nothing was installed."

    step "change to the installed directory"
    run cd "$PACKAGE_INSTALL_DIR"

    [ -z "$(ls)" ]                  && abort 1 "nothing was installed."

    #########################################################################################

    [ "$PACKAGE_USE_CARGO" = 1 ] && {
        run rm -f .crates.toml
        run rm -f .crates2.json
    }

    #########################################################################################

    for item in $PACKAGE_WRAPPER
    do
        S="${item%'|'*}"
        T="${item#*'|'}"

        wfetch "https://raw.githubusercontent.com/leleliu008/ndk-pkg-formula-repository-official-core/refs/heads/master/wrappers/$S" --no-buffer
        run mv "$S" "$T"
    done

    #########################################################################################

    [ -n "$PACKAGE_DOTWEAK" ] && {
        step "dotweak"

        cd "$PACKAGE_INSTALL_DIR"

        eval "
dotweak() {
$PACKAGE_DOTWEAK
}"
        dotweak
    }

    #########################################################################################

    __tweak_pc_files

    #########################################################################################

    run cd "$PACKAGE_INSTALL_DIR"

    # https://www.linuxfromscratch.org/blfs/view/stable-systemd/introduction/la-files.html
    # remove Libtool Archive (.la) files
    [ -d lib ] && find -L lib -maxdepth 1 -mindepth 1 -type f -name '*.la' -exec rm -v {} +

    #########################################################################################

    step "generate MANIFEST.txt"
    run install -d .ndk-pkg/dependencies/lib/
    find -not -path . -a -not -path ./.ndk-pkg -a -not -path './.ndk-pkg/*' -printf '%y|%P\n' > .ndk-pkg/MANIFEST.txt

    #########################################################################################

    if [ "$TARGET_PLATFORM_ARCH" = armv7a ] ; then
        ANDROID_NDK_SYSTEM_LIBRARY_DIR="$ANDROID_NDK_SYSROOT/usr/lib/arm-linux-androideabi"
    else
        ANDROID_NDK_SYSTEM_LIBRARY_DIR="$ANDROID_NDK_SYSROOT/usr/lib/$TARGET_PLATFORM_ARCH-linux-android"
    fi

    step "docheck"

    unset FILES_NEED_TO_BE_SET_RPATH

    unset NEEDED_LIBCXX_SHARED

    __check_elf_files

    find .ndk-pkg/dependencies/lib -type f -exec "$PATCHELF" --set-rpath '$ORIGIN' {} \;

    if [ "$NEEDED_LIBCXX_SHARED" = 1 ] ; then
        run cp -L "$ANDROID_NDK_SYSTEM_LIBRARY_DIR/libc++_shared.so" .ndk-pkg/dependencies/lib/
    fi

    [ -n "$FILES_NEED_TO_BE_SET_RPATH" ] && {
        step "set rpath for ELF files"

        KVs="$(printf '%s\n' "$FILES_NEED_TO_BE_SET_RPATH" | sort | uniq)"

        for KV in $KVs
        do
            K="${KV%|*}"
            V="${KV#*|}"

            [ "$V" = 1 ] && V='.ndk-pkg/dependencies/lib'

            RELATIVE_PATH="$(realpath -m --relative-to="${K%/*}" "$V")"

            run patchelf --add-rpath "'\$ORIGIN/$RELATIVE_PATH'" "$K"
        done
    }

    #########################################################################################

    run rmdir -p --ignore-fail-on-non-empty .ndk-pkg/dependencies/lib

    run cd .ndk-pkg

    #########################################################################################

    run mv "$TOOLCHAIN_CONFIG_NATIVE" .
    run mv "$TOOLCHAIN_CONFIG_TARGET" .

    #########################################################################################

    for item in 'FAQ*' 'TODO*' 'NEWS*' 'THANKS*' 'README*' 'COPYING*' 'LICENSE*' 'AUTHORS*' 'CHANGES*' 'CHANGELOG*' 'CONTRIBUTORS*' 'CONTRIBUTING*'
    do
        find -L "$PACKAGE_INSTALLING_SRC_DIR" -mindepth 1 -maxdepth 1 -type f -iname "$item" -exec cp -L {} . \;
    done

    #########################################################################################

    [ -n "$PACKAGE_DEP_PKG" ] && {
        step "install dependency graph files"

        run mv "$PACKAGE_WORKING_DIR/dependencies.*" .

        step "install dependency formulas"

        install -d dependencies/

        for DEPENDENT_PACKAGE_NAME in $RECURSIVE_DEPENDENT_PACKAGE_NAMES
        do
            cp "$SESSION_DIR/$DEPENDENT_PACKAGE_NAME.yml" dependencies/
        done
    }

    #########################################################################################

    for dir in "$PACKAGE_BCACHED_DIR" "$PACKAGE_BSCRIPT_DIR"
    do
        if [ -f "$dir/config.log" ] ; then
            mv  "$dir/config.log" .
        fi
        if [ -f "$dir/compile_commands.json" ] ; then
            mv  "$dir/compile_commands.json" .
        fi
    done

    #########################################################################################

    step "generate RECEIPT.yml"

    cp "$PACKAGE_FORMULA_FILEPATH" RECEIPT.yml

    gsed -i '/^#src-url: dir:/d' RECEIPT.yml

    gsed -i "1i pkgname: $PACKAGE_NAME" RECEIPT.yml

    grep -q '^pkgtype: ' RECEIPT.yml || gsed -i "/^pkgname:/a pkgtype: $PACKAGE_PKGTYPE" RECEIPT.yml
    grep -q '^version: ' RECEIPT.yml || gsed -i "/^pkgtype:/a version: $PACKAGE_VERSION" RECEIPT.yml
    grep -q '^web-url: ' RECEIPT.yml || gsed -i "/^summary:/a web-url: $PACKAGE_GIT_URL" RECEIPT.yml
    grep -q '^git-url: ' RECEIPT.yml || gsed -i "/^web-url:/a git-url: $PACKAGE_GIT_URL" RECEIPT.yml
    grep -q '^bsystem: ' RECEIPT.yml || gsed -i "/^install:/i bsystem: $PACKAGE_BSYSTEM" RECEIPT.yml
    grep -q '^binbstd: ' RECEIPT.yml || gsed -i "/^bsystem:/a binbstd: $PACKAGE_BINBSTD" RECEIPT.yml

    [ -n "$PACKAGE_GIT_SHA" ] && {
        grep -q '^git-sha: ' RECEIPT.yml || {
            gsed -i "/^git-url:/a git-sha: $PACKAGE_GIT_SHA" RECEIPT.yml
        }

        grep -q '^git-sha: ' RECEIPT.yml || {
            gsed -i "3i git-sha: $PACKAGE_GIT_SHA" RECEIPT.yml
        }
    }

    [ -n "$PACKAGE_DEP_UPP" ] && {
        if grep -q '^dep-upp: ' RECEIPT.yml ; then
            gsed -i "/^dep-upp: /c dep-upp: $PACKAGE_DEP_UPP" RECEIPT.yml
        else
            gsed -i "/^bsystem: /i dep-upp: $PACKAGE_DEP_UPP" RECEIPT.yml
        fi
    }

    cat >> RECEIPT.yml <<EOF
ndkvers: $ANDROID_NDK_VERSION
profile: $PROFILE
builtfor: $TARGET_PLATFORM_SPEC
builtby: ndk-pkg-$NDKPKG_VERSION
builtat: $TIMESTAMP_UNIX
builton:
    os-arch: $NATIVE_PLATFORM_ARCH
    os-kind: $NATIVE_PLATFORM_KIND
    os-type: $NATIVE_PLATFORM_TYPE
    os-libc: $NATIVE_PLATFORM_LIBC
    os-code: $NATIVE_PLATFORM_CODE
    os-name: $NATIVE_PLATFORM_NAME
    os-vers: $NATIVE_PLATFORM_VERS
    os-ncpu: $NATIVE_PLATFORM_NCPU
    os-euid: $NATIVE_PLATFORM_EUID
    os-egid: $NATIVE_PLATFORM_EGID
EOF

    if [ "$NATIVE_PLATFORM_TYPE" = linux ] ; then
        if command -v getconf > /dev/null ; then
            NATIVE_PLATFORM_LIBC_VERSION="$(getconf GNU_LIBC_VERSION 2>/dev/null | cut -d ' ' -f2)"
            if [ -n "$NATIVE_PLATFORM_LIBC_VERSION" ] ; then
                gsed -i "/os-libc: /s|$|-$NATIVE_PLATFORM_LIBC_VERSION|" RECEIPT.yml
            fi
        fi
    fi

    #########################################################################################

    step "generate index"
    run cd "$NDKPKG_PACKAGE_INSTALLED_ROOT/$TARGET_PLATFORM_SPEC"
    run ln -s -f -T "$PACKAGE_INSTALL_SHA" "$PACKAGE_NAME"

    #########################################################################################

    step "show installed files in tree-like format"
    run tree --dirsfirst -a "$PACKAGE_INSTALL_DIR"

    #########################################################################################

    [ "$ENABLE_CCACHE" = 1 ] && {
        step "show ccache statistics summary"
        note "Before Build:"
        run  cat "$PACKAGE_WORKING_DIR/ccache-s.txt"
        note "After  Build:"
        run  ccache -s
    }

    [ "$REQUEST_TO_KEEP_SESSION_DIR" != 1 ] && {
        step "delete the working directory"
        run rm -rf "$PACKAGE_WORKING_DIR"
    }

    #########################################################################################

    printf '\n%b\n' "${COLOR_PURPLE}✅️  ${COLOR_OFF}${COLOR_GREEN}${1} was successfully installed.${COLOR_OFF}${COLOR_PURPLE}${COLOR_OFF}"

    if [ -n "$PACKAGE_CAVEATS" ] ; then
        printf '\n%b\n' "${COLOR_YELLOW}⚠️  Caveats:${COLOR_OFF}\n\n$PACKAGE_CAVEATS" >&2
    fi
}

__check_elf_files() {
    CHECKER="$NDKPKG_CORE_DIR/check-if-has-dynamic-section"

    while read -r LINE
    do
        FILETYPE="${LINE%%|*}"
        FILEPATH="${LINE##*|}"

        [ "$FILETYPE" = f ] || continue

        FILE_HEADER_ACTUAL="$(xxd -u -p -l 20 "$FILEPATH")"

        case $FILE_HEADER_ACTUAL in
            7F454C46*) ;;
            *)  printf "NOT an ELF file: %s\n" "$FILEPATH" >&2 ; continue
        esac

        # http://www.sco.com/developers/gabi/latest/ch4.eheader.html
        ELF_TYPE="$(printf '%s\n' "$FILE_HEADER_ACTUAL" | cut -c33-34)"

        case $TARGET_PLATFORM_ARCH in
            armv7a)  FILE_HEADER_EXPACT="7F454C46010101000000000000000000${ELF_TYPE}002800" ;;
            aarch64) FILE_HEADER_EXPACT="7F454C46020101000000000000000000${ELF_TYPE}00B700" ;;
            i686)    FILE_HEADER_EXPACT="7F454C46010101000000000000000000${ELF_TYPE}000300" ;;
            x86_64)  FILE_HEADER_EXPACT="7F454C46020101000000000000000000${ELF_TYPE}003E00" ;;
        esac

        if [ "$FILE_HEADER_EXPACT" != "$FILE_HEADER_ACTUAL" ] ; then
            abort 1 "ELF file header mismatch: $FILEPATH\n    expect : $FILE_HEADER_EXPACT\n    actual : $FILE_HEADER_ACTUAL"
        fi

        #####################################################################

        # 03 means it is a shared library or dynamically linked executable
        [ "$ELF_TYPE" = '03' ] || continue

        "$CHECKER" "$FILEPATH" || continue

        # patchelf would report a error if there is no '.interp' section in a ELF file
        DYNAMIC_LINKER_PATH="$(patchelf --print-interpreter "$FILEPATH" 2>/dev/null || true)"

        if [ -n  "$DYNAMIC_LINKER_PATH" ] ; then
            if [ "$DYNAMIC_LINKER_PATH" != "$ANDROID_DYNAMIC_LINKER_PATH" ] ; then
                abort 1 "invalid ELF file: $FILEPATH\n    dynamic linker mismatch\n    expect : $ANDROID_DYNAMIC_LINKER_PATH\n    actual : $DYNAMIC_LINKER_PATH"
            fi

            # https://source.android.com/security/enhancements/enhancements50
            # Android 5.0 and later, a dynamically linked executable must be a PIE(Position Independent Executable)
            if ! "$READELF" -d "$FILEPATH" | grep FLAGS_1 | grep -q PIE ; then
                abort 1 "invalid ELF file: $FILEPATH\n    Android 5.0 and later requires dynamically linked executable to support PIE (position-independent executables)."
            fi
        fi

        #####################################################################

        # A dynamically linked executable always have the .interp section.
        # In general, a shared library would not have the .interp section, but that is not always the case, for example, libcap/lib/libpsx.so is not only a library but also a executable.

        #####################################################################

        # On Android, if a shared library is supposed to be linked by other shared libraries, then it must have the SONAME, otherwise, the shared library who link this library will use the full path to gen the DT_NEEDED
        # https://github.com/android/ndk/issues/1865
        # https://android.googlesource.com/platform/bionic/+/master/android-changes-for-ndk-developers.md

        case "${FILEPATH##*/}" in
            lib*.so|lib*.so.*)
                # http://www.sco.com/developers/gabi/latest/ch5.dynamic.html#dynamic_section
                SONAME="$(patchelf --print-soname "$FILEPATH")"

                if [ -z "$SONAME" ] ; then
                    abort 1 "invalid ELF file: $FILEPATH\n    SONAME was not set in .dynamic section"
                fi
        esac

        #####################################################################

        patchelf --remove-rpath "$FILEPATH"

        #####################################################################

        __check_DT_NEEDED "$FILEPATH"
    done < .ndk-pkg/MANIFEST.txt
}

# __check_DT_NEEDED <ELF-FILE-PATH>
  __check_DT_NEEDED() {
    X="$(printf '%s\n' "$1" | tr / _)"
    Y="$PACKAGE_WORKING_DIR/map/$X"

    if [ -f "$Y" ] ; then
        return 0
    else
        touch "$Y"
    fi

    #####################################################

    NEEDED_SHARED_LIBRARY_FILENAMEs="$(patchelf --print-needed "$1")"

    for NEEDED_SHARED_LIBRARY_FILENAME in $NEEDED_SHARED_LIBRARY_FILENAMEs
    do
        case $NEEDED_SHARED_LIBRARY_FILENAME in
            libc++_shared.so)
                NEEDED_LIBCXX_SHARED=1
                continue
                ;;
            libclang_rt.*.so)
                continue
                ;;
        esac

        if [ "$NEEDED_SHARED_LIBRARY_FILENAME" != 'libz.so' ] ; then
            if [ -f "$ANDROID_NDK_SYSTEM_LIBRARY_DIR/$TARGET_PLATFORM_VERS/$NEEDED_SHARED_LIBRARY_FILENAME" ] ; then
                continue
            fi
        fi

        #####################################################

        NEEDED_SHARED_LIBRARY_FILEPATH=

        case $1 in
            /*) ;;
            *)
                if [ -d lib ] ; then
                    NEEDED_SHARED_LIBRARY_FILEPATH="lib/$NEEDED_SHARED_LIBRARY_FILENAME"

                    [ -f "$NEEDED_SHARED_LIBRARY_FILEPATH" ] || {
                        unset NEEDED_SHARED_LIBRARY_FILEPATH
                        NEEDED_SHARED_LIBRARY_FILEPATH="$(find -L lib -type f -name "$NEEDED_SHARED_LIBRARY_FILENAME" -print -quit)"
                    }

                    [ -n "$NEEDED_SHARED_LIBRARY_FILEPATH" ] && {
                        FILES_NEED_TO_BE_SET_RPATH="$FILES_NEED_TO_BE_SET_RPATH
$1|${NEEDED_SHARED_LIBRARY_FILEPATH%/*}"
                    }
                fi
        esac

        #####################################################

        if [ -z "$NEEDED_SHARED_LIBRARY_FILEPATH" ] ; then
            if [ -n "$RECURSIVE_DEPENDENT_PACKAGE_NAMES" ] ; then
                for DEPENDENT_PACKAGE_NAME in $RECURSIVE_DEPENDENT_PACKAGE_NAMES
                do
                    NEEDED_SHARED_LIBRARY_ROOT_DIR="$NDKPKG_PACKAGE_INSTALLED_ROOT/$TARGET_PLATFORM_SPEC/$DEPENDENT_PACKAGE_NAME/lib"

                    [ -d "$NEEDED_SHARED_LIBRARY_ROOT_DIR" ] || continue

                    NEEDED_SHARED_LIBRARY_FILEPATH="$NEEDED_SHARED_LIBRARY_ROOT_DIR/$NEEDED_SHARED_LIBRARY_FILENAME"

                    [ -f "$NEEDED_SHARED_LIBRARY_FILEPATH" ] || {
                        unset NEEDED_SHARED_LIBRARY_FILEPATH
                        NEEDED_SHARED_LIBRARY_FILEPATH="$(find -L "$NEEDED_SHARED_LIBRARY_ROOT_DIR" -type f -name "$NEEDED_SHARED_LIBRARY_FILENAME" -print -quit)"
                    }

                    [ -n "$NEEDED_SHARED_LIBRARY_FILEPATH" ] && {
                        case $1 in
                            /*) ;;
                            *)  FILES_NEED_TO_BE_SET_RPATH="$FILES_NEED_TO_BE_SET_RPATH
$1|1"
                        esac

                        if [ ! -f ".ndk-pkg/dependencies/lib/$NEEDED_SHARED_LIBRARY_FILENAME" ] ; then
                            run cp -L "$NEEDED_SHARED_LIBRARY_FILEPATH" .ndk-pkg/dependencies/lib/
                        fi

                        break
                    }
                done
            fi
        fi

        if [ -n "$NEEDED_SHARED_LIBRARY_FILEPATH" ] ; then
            __check_DT_NEEDED "$NEEDED_SHARED_LIBRARY_FILEPATH"
        fi
    done
}

__tweak_pc_files() {
    unset PC_FILES

    for item in lib share
    do
        PC_FILES_LIVEDIR="$PACKAGE_INSTALL_DIR/$item/pkgconfig"

        if [ -d        "$PC_FILES_LIVEDIR" ] ; then
            fs="$(find "$PC_FILES_LIVEDIR" -type f -name '*.pc')"

            if [ -n "$fs" ] ; then
                PC_FILES="$PC_FILES $fs"
            fi
        fi
    done

    for pcfile in $PC_FILES
    do
        gsed -i "s|$PACKAGE_INSTALL_DIR|\${pcfiledir}/../..|g" "$pcfile"

        gsed -i "s|-I$NDKPKG_HOME[^' ]*||g"   "$pcfile"
        gsed -i "s|-L$NDKPKG_HOME[^' ]*||g"   "$pcfile"
        gsed -i "s|-L$SYSROOT[^' ]*||g"       "$pcfile"
        gsed -i "s|--sysroot=$SYSROOT||"      "$pcfile"
        gsed -i 's|-flto||g'                  "$pcfile"
        gsed -i 's|-lpthread||g'              "$pcfile"
        gsed -i 's|-Wl,--strip-debug||g'      "$pcfile"

        gsed -i "s|${NDKPKG_HOME}/.*/lib\(.*\)\.so|-l\1|g" "$pcfile"
        gsed -i "s|${NDKPKG_HOME}/.*/lib\(.*\)\.a|-l\1|g"  "$pcfile"

        if grep -q '^Libs.private:' "$pcfile" ; then
            if grep -q '^Libs:' "$pcfile" ; then
                LIBS_PRIVATE=$(gsed -n '/^Libs.private:/p' "$pcfile" | cut -c14-)
                gsed -i "/Libs:/s|\$|$LIBS_PRIVATE|" "$pcfile"
                gsed -i '/Libs.private/d' "$pcfile"
            else
                gsed -i 's|Libs.private:|Libs:|' "$pcfile"
            fi
        fi

        if grep -q '^Requires.private:' "$pcfile" ; then
            if grep -q '^Requires:' "$pcfile" ; then
                REQUIRES_PRIVATE=$(gsed -n '/Requires.private:/p' "$pcfile" | cut -c18-)
                gsed -i "/Requires:/s|\$|$REQUIRES_PRIVATE|" "$pcfile"
                gsed -i '/Requires.private:/d' "$pcfile"
            else
                gsed -i 's|Requires.private:|Requires:|' "$pcfile"
            fi
        fi
    done
}

install_incs() {
    while [ -n "$1" ]
    do
        unset X1
        unset X2
        X1=$(printf '%s\n' "$1" | cut -d: -f1)
        X2=$(printf '%s\n' "$1" | cut -d: -f2)

        if [ "$X1" = "$X2" ] ; then
            unset X2
        fi

        install -v -d         "$PACKAGE_INSTALL_DIR/include/$X2"
        install -v -m 644 $X1 "$PACKAGE_INSTALL_DIR/include/$X2"

        shift
    done
}

install_libs() {
    install -v -d "$PACKAGE_INSTALL_DIR/lib"
    for item in "$@"
    do
        case $item in
            *.a) install -v -m 644 "$item" "$PACKAGE_INSTALL_DIR/lib" ;;
            *)   install -v -m 755 "$item" "$PACKAGE_INSTALL_DIR/lib" ;;
        esac
    done
}

writepc() {
    install -v -d "$PACKAGE_INSTALL_DIR/lib/pkgconfig" &&
    cat >         "$PACKAGE_INSTALL_DIR/lib/pkgconfig/$1.pc"
}

install_pcfs() {
    install -v -d          "$PACKAGE_INSTALL_DIR/lib/pkgconfig" &&
    install -v -m 644 "$@" "$PACKAGE_INSTALL_DIR/lib/pkgconfig"
}

install_bins() {
    install -v -d          "$PACKAGE_INSTALL_DIR/bin" &&
    install -v -m 755 "$@" "$PACKAGE_INSTALL_DIR/bin"
}

install_etcs() {
    install -v -d          "$PACKAGE_INSTALL_DIR/etc" &&
    install -v -m 644 "$@" "$PACKAGE_INSTALL_DIR/etc"
}

install_mans() {
    for item in "$@"
    do
        unset NUMBER
        NUMBER=$(printf '%s\n' "$item" | cut -c ${#item}-${#item})
        case $NUMBER in
            [1-8]);;
            *)    abort 1 "$item: not a manpage."
        esac
        install -v -d             "$PACKAGE_INSTALL_DIR/share/man/man$NUMBER" &&
        install -v -m 644 "$item" "$PACKAGE_INSTALL_DIR/share/man/man$NUMBER"
    done
}

# install_completion <fish|bash|zsh> <COMMAND> <FILE-PATH>
  install_completion() {
    case $1 in
        bash)
            install -v -d          "$PACKAGE_INSTALL_DIR/share/bash/completions" &&
            install -v -m 644 "$3" "$PACKAGE_INSTALL_DIR/share/bash/completions/$2"
            ;;
        fish)
            install -v -d          "$PACKAGE_INSTALL_DIR/share/fish/vendor_completions.d" &&
            install -v -m 644 "$3" "$PACKAGE_INSTALL_DIR/share/fish/vendor_completions.d/$2.fish"
            ;;
        zsh)
            install -v -d          "$PACKAGE_INSTALL_DIR/share/zsh/site-functions" &&
            install -v -m 644 "$3" "$PACKAGE_INSTALL_DIR/share/zsh/site-functions/_$2"
            ;;
        *)  abort 1 "install_completion unsupported shell: $1"
    esac
}

__record_installed_files_of_the_given_package() {
    if [ -z "$2" ] ; then
        INSTALLED_FILES_FILEPATH="$PACKAGE_INSTALL_DIR/installed-files"
        printf '%s\n' "-- Installing: $INSTALLED_FILES_FILEPATH"

        touch "$INSTALLED_FILES_FILEPATH"
        return 0

        # TODO
        exec 7> "$INSTALLED_FILES_FILEPATH"

        __record_installed_files_of_the_given_package "$1" "$PACKAGE_INSTALL_DIR"

        exec 7>&-

        gsed -i "s|$PACKAGE_INSTALL_DIR/||" "$INSTALLED_FILES_FILEPATH"
    else
        for file in $(ls $2)
        do
            file="$2/$file"
            if [ -d "$file" ] ; then
                __record_installed_files_of_the_given_package "$1" "$file"
            else
                printf '%s %s\n' $(md5sum "$file") "$file" >&7
            fi
        done
    fi
}

gnw() {
    run gn gen "$PACKAGE_BCACHED_DIR" --root="$PACKAGE_BSCRIPT_DIR" "'--args=$*'"
    run ninja --version
    run ninja --verbose
}

gow() {
    if [ "$VERBOSE_GO" = 1 ] ; then
        run "go env | bat --language=bash --paging=never --style=plain"
    fi

    # https://pkg.go.dev/cmd/go
    # https://pkg.go.dev/cmd/link

    unset GO_BUILD_ARGS
    unset GO_BUILD_ARGV_V
    unset GO_BUILD_ARGV_X
    unset GO_BUILD_ARGV_O
    unset GO_BUILD_ARGV_MOD
    unset GO_BUILD_ARGV_TAGS
    unset GO_BUILD_ARGV_LDFLAGS

    unset GO_BUILD_ARGS_EXTRA

    while [ -n "$1" ]
    do
        case $1 in
            -v) shift ; GO_BUILD_ARGV_V='-v' ;;
            -x) shift ; GO_BUILD_ARGV_X='-x' ;;
            -o) shift ; GO_BUILD_ARGV_O="$1" ; shift ;;
            -X) shift
                if [ -z "$GO_BUILD_ARGV_LDFLAGS" ] ; then
                    GO_BUILD_ARGV_LDFLAGS="-X $1"
                else
                    GO_BUILD_ARGV_LDFLAGS="$GO_BUILD_ARGV_LDFLAGS -X $1"
                fi
                shift
                ;;
            -ldflags)
                shift
                if [ -z "$GO_BUILD_ARGV_LDFLAGS" ] ; then
                    GO_BUILD_ARGV_LDFLAGS="$1"
                else
                    GO_BUILD_ARGV_LDFLAGS="$1 $GO_BUILD_ARGV_LDFLAGS"
                fi
                shift
                ;;
            *)  GO_BUILD_ARGS_EXTRA="$GO_BUILD_ARGS_EXTRA $1" ; shift
        esac
    done

    GO_BUILD_ARGS='-trimpath'

    if [ -z "$GO_BUILD_ARGV_V" ] ; then
        if [ "$VERBOSE_GO" = 1 ] ; then
            GO_BUILD_ARGS="$GO_BUILD_ARGS -v"
        fi
    else
        GO_BUILD_ARGS="$GO_BUILD_ARGS -v"
    fi

    if [ -z "$GO_BUILD_ARGV_X" ] ; then
        if [ "$DEBUG_GO" = 1 ] ; then
            GO_BUILD_ARGS="$GO_BUILD_ARGS -x"
        fi
    else
        GO_BUILD_ARGS="$GO_BUILD_ARGS -x"
    fi

    if [ "$PROFILE" = release ] ; then
        GO_BUILD_ARGV_LDFLAGS="$GO_BUILD_ARGV_LDFLAGS -s -w"
    fi

    if [ "$NATIVE_PLATFORM_KIND" != darwin ] ; then
        if [ "$PACKAGE_CREATE_FULLY_STATICALLY_LINKED_EXECUTABLE" = 1 ] && [ "$CGO_ENABLED" -eq 1 ] ; then
            GO_BUILD_ARGV_LDFLAGS="$GO_BUILD_ARGV_LDFLAGS -linkmode external \"-extldflags=-static\""
        fi
    fi

    GO_BUILD_ARGS="$GO_BUILD_ARGS -ldflags '$GO_BUILD_ARGV_LDFLAGS'"

    if [ -z "$GO_BUILD_ARGV_O" ] ; then
        GO_BUILD_ARGS="$GO_BUILD_ARGS -o $PACKAGE_BCACHED_DIR/"
    else
        GO_BUILD_ARGS="$GO_BUILD_ARGS -o $PACKAGE_BCACHED_DIR/$GO_BUILD_ARGV_O"
    fi

    GO_BUILD_ARGS="$GO_BUILD_ARGS $GO_BUILD_ARGS_EXTRA"

    # shellcheck disable=SC2086
    run go build $GO_BUILD_ARGS

    for item in $(ls "$PACKAGE_BCACHED_DIR")
    do
        case $item in
            *.a)  run install_libs "$PACKAGE_BCACHED_DIR/$item" ;;
            *.so) run install_libs "$PACKAGE_BCACHED_DIR/$item" ;;
            *)    run install_bins "$PACKAGE_BCACHED_DIR/$item" ;;
        esac
    done
}

cargow() {
    [ "$TERMUX" = 1 ] || run rustup target add "$RUST_TARGET"

    case $1 in
        build)
            # https://doc.rust-lang.org/cargo/commands/cargo-clean.html
            # https://doc.rust-lang.org/cargo/commands/cargo-build.html

            unset CARGO_BUILD_ARGS
            unset CARGO_BUILD_ARG_VV
            unset CARGO_BUILD_ARG_TARGET
            unset CARGO_BUILD_ARG_RELEASE

            for arg in $@
            do
                case $arg in
                    --vv)      CARGO_BUILD_ARG_VV=set      ;;
                    --target)  CARGO_BUILD_ARG_TARGET=set  ;;
                    --release) CARGO_BUILD_ARG_RELEASE=set ;;
                esac
            done

            CARGO_BUILD_ARGS="$@"

            if [ -z "$CARGO_BUILD_ARG_VV" ] ; then
                if [ "$DEBUG_CARGO" = 1 ] ; then
                    CARGO_BUILD_ARGS="$CARGO_BUILD_ARGS -vv"
                fi
            fi

            if [ -z "$CARGO_BUILD_ARG_RELEASE" ] ; then
                CARGO_BUILD_ARGS="$CARGO_BUILD_ARGS --release"
            fi

            if [ -z "$CARGO_BUILD_ARG_TARGET" ] ; then
                CARGO_BUILD_ARGS="$CARGO_BUILD_ARGS --target $RUST_TARGET"
            fi

            run cargo clean && run cargo $CARGO_BUILD_ARGS
            ;;
        install)
            # https://doc.rust-lang.org/cargo/commands/cargo-clean.html
            # https://doc.rust-lang.org/cargo/commands/cargo-install.html

            unset CARGO_INSTALL_ARGS
            unset CARGO_INSTALL_ARG_TARGET
            unset CARGO_INSTALL_ARG_PATH
            unset CARGO_INSTALL_ARG_ROOT
            unset CARGO_INSTALL_ARG_VV

            for arg in $@
            do
                case $arg in
                    --target) CARGO_INSTALL_ARG_TARGET=set ;;
                    --path)   CARGO_INSTALL_ARG_PATH=set   ;;
                    --root)   CARGO_INSTALL_ARG_ROOT=set   ;;
                    --vv)     CARGO_INSTALL_ARG_VV=set     ;;
                esac
            done

            CARGO_INSTALL_ARGS="$@"

            if [ -z "$CARGO_BUILD_ARG_VV" ] ; then
                if [ "$DEBUG_CARGO" = 1 ] ; then
                    CARGO_INSTALL_ARGS="$CARGO_INSTALL_ARGS -vv"
                fi
            fi

            if [ -z "$CARGO_INSTALL_ARG_TARGET" ] ; then
                CARGO_INSTALL_ARGS="$CARGO_INSTALL_ARGS --target $RUST_TARGET"
            fi

            if [ -z "$CARGO_INSTALL_ARG_PATH" ] ; then
                CARGO_INSTALL_ARGS="$CARGO_INSTALL_ARGS --path $PACKAGE_BSCRIPT_DIR"
            fi

            if [ -z "$CARGO_INSTALL_ARG_ROOT" ] ; then
                CARGO_INSTALL_ARGS="$CARGO_INSTALL_ARGS --root=$PACKAGE_INSTALL_DIR"
            fi

            run cargo clean && run cargo $CARGO_INSTALL_ARGS
            ;;
        cbuild|cinstall)
            unset CARGO_CINSTALL_ARGS
            unset CARGO_CINSTALL_ARG_Q
            unset CARGO_CINSTALL_ARG_V
            unset CARGO_CINSTALL_ARG_VV
            unset CARGO_CINSTALL_ARG_DEBUG
            unset CARGO_CINSTALL_ARG_RELEASE
            unset CARGO_CINSTALL_ARG_TARGET
            unset CARGO_CINSTALL_ARG_PREFIX

            for arg in $@
            do
                case $arg in
                    -q|--quiet)   CARGO_CINSTALL_ARG_Q=set       ;;
                    -v|--verbose) CARGO_CINSTALL_ARG_V=set       ;;
                    -vv)          CARGO_CINSTALL_ARG_VV=set      ;;
                    --debug)      CARGO_CINSTALL_ARG_DEBUG=set   ;;
                    --release)    CARGO_CINSTALL_ARG_RELEASE=set ;;
                    --target)     CARGO_CINSTALL_ARG_TARGET=set  ;;
                    --prefix)     CARGO_CINSTALL_ARG_PREFIX=set  ;;
                esac
            done

            CARGO_CINSTALL_ARGS="$@"

            if [ -z "$CARGO_CINSTALL_ARG_Q" ] && [ -z "$CARGO_CINSTALL_ARG_V" ] && [ -z "$CARGO_CINSTALL_ARG_VV" ] ; then
                if [ "$DEBUG_CARGO" = 1 ] ; then
                    CARGO_CINSTALL_ARGS="$CARGO_CINSTALL_ARGS -vv"
                fi
            fi

            if [ -z "$CARGO_CINSTALL_ARG_DEBUG" ] && [ -z "$CARGO_CINSTALL_ARG_RELEASE" ] ; then
                CARGO_CINSTALL_ARGS="$CARGO_CINSTALL_ARGS --release"
            fi

            if [ -z "$CARGO_CINSTALL_ARG_TARGET" ] ; then
                CARGO_CINSTALL_ARGS="$CARGO_CINSTALL_ARGS --target $RUST_TARGET"
            fi

            if [ -z "$CARGO_CINSTALL_ARG_PREFIX" ] ; then
                CARGO_CINSTALL_ARGS="$CARGO_CINSTALL_ARGS --prefix $PACKAGE_INSTALL_DIR"
            fi

            run cargo $CARGO_CINSTALL_ARGS
            ;;
        *) cargo $@
    esac
}

# }}}
##############################################################################
# {{{ waf

waf() {
    run python3 ./waf "$@"
}

# }}}
##############################################################################
# {{{ configure

configure() {
    unset CONFIGURE_ONLY

    if [ "$1" = only ] ; then
        CONFIGURE_ONLY=1
        shift
    fi

    if [ "$BUILD_FOR_NATIVE" = 1 ] ; then
        if run "$PACKAGE_BSCRIPT_DIR"/configure \
            --prefix="$PACKAGE_INSTALL_DIR" \
            $@ ; then
            echo
        else
            if [ -f "$PACKAGE_BCACHED_DIR/config.log" ] ; then
                run cat "$PACKAGE_BCACHED_DIR/config.log"
            elif [ -f "$PACKAGE_BSCRIPT_DIR/config.log" ] ; then
                run cat "$PACKAGE_BSCRIPT_DIR/config.log"
            fi
            return 1
        fi
    else
        # https://www.gnu.org/software/autoconf/manual/autoconf-2.71/html_node/Generic-Functions.html

        export ac_cv_search_log=-lm
        export ac_cv_search_ceil=-lm

        export ac_cv_lib_m_sqrt=yes

        export ac_cv_func_pow=yes
        export ac_cv_func_ffsl=yes
        export ac_cv_func_free=yes
        export ac_cv_func_calloc=yes
        export ac_cv_func_malloc=yes
        export ac_cv_func_realloc=yes
        export ac_cv_func_memset=yes
        export ac_cv_func_strchr=yes
        export ac_cv_func_strstr=yes
        export ac_cv_func_stpcpy=yes
        export ac_cv_func_strcpy=yes
        export ac_cv_func_strtol=yes
        export ac_cv_func_strdup=yes
        export ac_cv_func_strndup=yes
        export ac_cv_func_wcslen=yes
        export ac_cv_func_isblank=yes
        export ac_cv_func_strerror=yes
        export ac_cv_func_snprintf=yes
        export ac_cv_func_faccessat=yes
        export ac_cv_func_sigsetmask=no
        export ac_cv_func_strcasecmp=yes
        export ac_cv_func_vsnprintf=yes

        export ac_cv_func_malloc_0_nonnull=yes
        export ac_cv_func_calloc_0_nonnull=yes
        export ac_cv_func_realloc_0_nonnull=yes

        # https://android.googlesource.com/platform/bionic/+/master/docs/32-bit-abi.md#is-32_bit-on-lp32-y2038
        if [ "$TARGET_PLATFORM_NBIT" -eq 32 ] ; then
            export ac_year2038_required=no
        fi

        # sys/stat.h int lchmod(const char* _Nonnull __path, mode_t __mode) __INTRODUCED_IN(36);
        # stdlib.h void qsort_r(void* _Nullable __array, size_t __n, size_t __size, int (* _Nonnull __comparator)(const void* _Nullable __lhs, const void* _Nullable __rhs, void* _Nullable __context), void* _Nullable __context) __INTRODUCED_IN(36);
        if [ "$TARGET_PLATFORM_VERS" -ge 36 ] ; then
            export ac_cv_func_lchmod=yes
            export ac_cv_func_qsort_r=yes
        else
            export ac_cv_func_lchmod=no
            export ac_cv_func_qsort_r=no
        fi

        # string.h  void* _Nonnull memset_explicit(void* _Nonnull __dst, int __ch, size_t __n) __INTRODUCED_IN(34);
        # stdio_ext.h  size_t __freadahead(FILE* _Nonnull __fp) __INTRODUCED_IN(34);
        if [ "$TARGET_PLATFORM_VERS" -ge 34 ] ; then
            export ac_cv_func_memset_explicit=yes
            export ac_cv_func___freadahead=yes
        else
            export ac_cv_func_memset_explicit=no
            export ac_cv_func___freadahead=no
        fi

        # sys/stat.h int statx(int __dir_fd, const char* _Nonnull __path, int __flags, unsigned __mask, struct statx* _Nonnull __buf) __INTRODUCED_IN(30);
        if [ "$TARGET_PLATFORM_VERS" -ge 30 ] ; then
            export ac_cv_func_statx=yes
        else
            export ac_cv_func_statx=no
        fi

        # malloc.h  void* _Nullable reallocarray(void* _Nullable __ptr, size_t __item_count, size_t __item_size) __BIONIC_ALLOC_SIZE(2, 3) __wur __INTRODUCED_IN(29);
        if [ "$TARGET_PLATFORM_VERS" -ge 29 ] ; then
            export ac_cv_func_reallocarray=yes
        else
            export ac_cv_func_reallocarray=no
        fi

        # unistd.h     int syncfs(int __fd) __INTRODUCED_IN(28);
        # sys/random.h ssize_t getrandom(void* _Nonnull __buffer, size_t __buffer_size, unsigned int __flags) __wur __INTRODUCED_IN(28);
        # stdio_ext.h  void __fseterr(FILE* _Nonnull __fp) __INTRODUCED_IN(28);
        # stdio_ext.h  int __freading(FILE* _Nonnull __fp) __INTRODUCED_IN(28);
        # stdio_ext.h  int __fwriting(FILE* _Nonnull __fp) __INTRODUCED_IN(28);
        # stdio.h      size_t fwrite_unlocked(const void* _Nonnull __buf, size_t __size, size_t __count, FILE* _Nonnull __fp) __INTRODUCED_IN(28);
        # extern       void* _Nonnull (*volatile _Nonnull __malloc_hook)(size_t __byte_count, const void* _Nonnull __caller) __INTRODUCED_IN(28);
        # spawn.h      int posix_spawnp(pid_t* _Nullable __pid, const char* _Nonnull __file, const posix_spawn_file_actions_t _Nullable * _Nullable __actions, const posix_spawnattr_t _Nullable * _Nullable __attr, char* const _Nonnull __argv[_Nonnull], char* const _Nullable __env[_Nullable]) __INTRODUCED_IN(28);
        if [ "$TARGET_PLATFORM_VERS" -ge 28 ] ; then
            export ac_cv_func_syncfs=yes
            export ac_cv_func_getrandom=yes
            export ac_cv_func___fseterr=yes
            export ac_cv_func___freading=yes
            export ac_cv_func___fwriting=yes
            export ac_cv_func___malloc_hook=yes
            export ac_cv_func_fwrite_unlocked=yes
            export ac_cv_func_posix_spawnp=yes
            export ac_cv_func_posix_spawn_file_actions_init=yes
            export ac_cv_func_posix_spawn_file_actions_addclose=yes
            export ac_cv_func_posix_spawn_file_actions_adddup2=yes
            export ac_cv_func_posix_spawn_file_actions_destroy=yes
        else
            export ac_cv_func_syncfs=no
            export ac_cv_func_getrandom=no
            export ac_cv_func___fseterr=no
            export ac_cv_func___freading=no
            export ac_cv_func___fwriting=no
            export ac_cv_func___malloc_hook=no
            export ac_cv_func_fwrite_unlocked=no
            export ac_cv_func_posix_spawnp=no
            export ac_cv_func_posix_spawn_file_actions_init=no
            export ac_cv_func_posix_spawn_file_actions_addclose=no
            export ac_cv_func_posix_spawn_file_actions_adddup2=no
            export ac_cv_func_posix_spawn_file_actions_destroy=no
        fi

        # stdio.h     char* _Nonnull ctermid(char* _Nullable __buf) __INTRODUCED_IN(26);
        # sys/time.h  int futimesat(int __dir_fd, const char* __BIONIC_COMPLICATED_NULLNESS __path, const struct timeval __times[_Nullable 2]) __INTRODUCED_IN(26);
        # sys/time.h  int lutimes(const char* _Nonnull __path, const struct timeval __times[_Nullable 2]) __INTRODUCED_IN(26);
        # langinfo.h  char* _Nonnull nl_langinfo(nl_item __item) __INTRODUCED_IN(26);
        # pwd.h  struct passwd* getpwent(void) __INTRODUCED_IN(26);
        if [ "$TARGET_PLATFORM_VERS" -ge 26 ] ; then
            export ac_cv_func_futimesat=yes
            export ac_cv_func_futimes=yes
            export ac_cv_func_lutimes=yes
            export ac_cv_func_ctermid=yes
            export ac_cv_func_setpwent=yes
            export ac_cv_func_getpwent=yes
            export ac_cv_func_endpwent=yes
            export ac_cv_func_nl_langinfo=yes
        else
            export ac_cv_func_futimesat=no
            export ac_cv_func_futimes=no
            export ac_cv_func_lutimes=no
            export ac_cv_func_ctermid=no
            export ac_cv_func_setpwent=no
            export ac_cv_func_getpwent=no
            export ac_cv_func_endpwent=no
            export ac_cv_func_nl_langinfo=no
        fi

        # grp.h  int getgrnam_r(const char* _Nonnull __name, struct group* __BIONIC_COMPLICATED_NULLNESS __group, char* _Nonnull __buf, size_t __n, struct group* _Nullable *_Nonnull __result) __INTRODUCED_IN(24);
        # grp.h  int getgrgid_r(gid_t __gid, struct group* __group, char* __buf, size_t __n, struct group** __result) __INTRODUCED_IN(24);
        if [ "$TARGET_PLATFORM_VERS" -ge 24 ] ; then
            export ac_cv_func_getgrnam_r=yes
            export ac_cv_func_getgrgid_r=yes
        else
            export ac_cv_func_getgrnam_r=no
            export ac_cv_func_getgrgid_r=no
        fi

        # stdio_ext.h  int __fsetlocking(FILE* _Nonnull __fp, int __type) __INTRODUCED_IN(23);
        # string.h     char* _Nonnull strerror_l(int __errno_value, locale_t _Nonnull __l) __INTRODUCED_IN(23);
        # stdlib.h     int mkostemp(char* _Nonnull __template, int __flags) __INTRODUCED_IN(23);
        # stdio.h      FILE* _Nullable fmemopen(void* _Nullable __buf, size_t __size, const char* _Nonnull __mode) __INTRODUCED_IN(23);
        if [ "$TARGET_PLATFORM_VERS" -ge 23 ] ; then
            export ac_cv_func_mempcpy=yes
            export ac_cv_func_wmempcpy=yes
            export ac_cv_func_mkostemp=yes
            export ac_cv_func_fmemopen=yes
            export ac_cv_func_strerror_l=yes
            export ac_cv_func___fsetlocking=yes
        else
            export ac_cv_func_mempcpy=no
            export ac_cv_func_wmempcpy=no
            export ac_cv_func_mkostemp=no
            export ac_cv_func_fmemopen=no
            export ac_cv_func_strerror_l=no
            export ac_cv_func___fsetlocking=no
        fi

        CONFIGURE_ARG_ENABLE_NLS=0
        CONFIGURE_ARG_ENABLE_RPATH=0
        CONFIGURE_ARG_ENABLE_LARGEFILE=1

        CONFIGURE_ARG_ENABLE_DEBUG=
        CONFIGURE_ARG_ENABLE_STATIC=
        CONFIGURE_ARG_ENABLE_SHARED=

        for arg in "$@"
        do
            case $arg in
                --enable-nls)      CONFIGURE_ARG_ENABLE_NLS=1 ;;
                --enable-nls=yes)  CONFIGURE_ARG_ENABLE_NLS=1 ;;
                --enable-nls=no)   CONFIGURE_ARG_ENABLE_NLS=0 ;;
                --disable-nls)     CONFIGURE_ARG_ENABLE_NLS=0 ;;

                --enable-rpath)     CONFIGURE_ARG_ENABLE_RPATH=1 ;;
                --enable-rpath=yes) CONFIGURE_ARG_ENABLE_RPATH=1 ;;
                --enable-rpath=no)  CONFIGURE_ARG_ENABLE_RPATH=0 ;;
                --disable-rpath)    CONFIGURE_ARG_ENABLE_RPATH=0 ;;

                --enable-largefile)     CONFIGURE_ARG_ENABLE_LARGEFILE=1 ;;
                --enable-largefile=yes) CONFIGURE_ARG_ENABLE_LARGEFILE=1 ;;
                --enable-largefile=no)  CONFIGURE_ARG_ENABLE_LARGEFILE=0 ;;
                --disable-largefile)    CONFIGURE_ARG_ENABLE_LARGEFILE=0 ;;

                --enable-debug)     CONFIGURE_ARG_ENABLE_DEBUG=1 ;;
                --enable-debug=yes) CONFIGURE_ARG_ENABLE_DEBUG=1 ;;
                --enable-debug=no)  CONFIGURE_ARG_ENABLE_DEBUG=0 ;;
                --disable-debug)    CONFIGURE_ARG_ENABLE_DEBUG=0 ;;

                --enable-static)     CONFIGURE_ARG_ENABLE_STATIC=1 ;;
                --enable-static=yes) CONFIGURE_ARG_ENABLE_STATIC=1 ;;
                --enable-static=no)  CONFIGURE_ARG_ENABLE_STATIC=0 ;;
                --disable-static)    CONFIGURE_ARG_ENABLE_STATIC=0 ;;

                --enable-shared)     CONFIGURE_ARG_ENABLE_SHARED=1 ;;
                --enable-shared=yes) CONFIGURE_ARG_ENABLE_SHARED=1 ;;
                --enable-shared=no)  CONFIGURE_ARG_ENABLE_SHARED=0 ;;
                --disable-shared)    CONFIGURE_ARG_ENABLE_SHARED=0 ;;
            esac
        done

        CONFIGURE_ARGS="--host='$TARGET_TRIPLE' --prefix='$PACKAGE_INSTALL_DIR' --disable-option-checking"

        if [ "$CONFIGURE_ARG_ENABLE_NLS" = 1 ] ; then
            CONFIGURE_ARGS="$CONFIGURE_ARGS --enable-nls"
        else
            CONFIGURE_ARGS="$CONFIGURE_ARGS --disable-nls"
        fi

        if [ "$CONFIGURE_ARG_ENABLE_RPATH" = 1 ] ; then
            CONFIGURE_ARGS="$CONFIGURE_ARGS --enable-rpath"
        else
            CONFIGURE_ARGS="$CONFIGURE_ARGS --disable-rpath"
        fi

        if [ "$CONFIGURE_ARG_ENABLE_LARGEFILE" = 1 ] ; then
            CONFIGURE_ARGS="$CONFIGURE_ARGS --enable-largefile"
        else
            CONFIGURE_ARGS="$CONFIGURE_ARGS --disable-largefile"
        fi

        if [ -z "$CONFIGURE_ARG_ENABLE_DEBUG" ] ; then
            case $PROFILE in
                debug)   CONFIGURE_ARGS="$CONFIGURE_ARGS --enable-debug"  ;;
                release) CONFIGURE_ARGS="$CONFIGURE_ARGS --disable-debug" ;;
            esac
        fi

        if [ -z "$CONFIGURE_ARG_ENABLE_STATIC" ] ; then
            CONFIGURE_ARGS="$CONFIGURE_ARGS --enable-static"
        fi

        if [ -z "$CONFIGURE_ARG_ENABLE_SHARED" ] ; then
            if [ "$PACKAGE_CREATE_FULLY_STATICALLY_LINKED_EXECUTABLE" = 1 ] || [ "$PACKAGE_CREATE_MOSTLY_STATICALLY_LINKED_EXECUTABLE" = 1 ] ; then
                CONFIGURE_ARGS="$CONFIGURE_ARGS --disable-shared"
            else
                CONFIGURE_ARGS="$CONFIGURE_ARGS --enable-shared"
            fi
        fi

        # https://android.googlesource.com/platform/bionic/+/master/docs/32-bit-abi.md#is-32_bit-on-lp32-y2038
        if [ "$TARGET_PLATFORM_NBIT" = 32 ] ; then
            CONFIGURE_ARGS="$CONFIGURE_ARGS --disable-year2038"
        fi

        CONFIGURE_ENVS="$CONFIGURE_ENVS --with-pic
            CC='$CC'
            CFLAGS='$CFLAGS'
            CXX='$CXX'
            CXXFLAGS='$CXXFLAGS'
            CPP='$CPP'
            CPPFLAGS='$CPPFLAGS'
            LDFLAGS='$LDFLAGS'
            AR='$AR'
            RANLIB='$RANLIB'
            PKG_CONFIG='$PKG_CONFIG'
            PKG_CONFIG_PATH='$PKG_CONFIG_PATH'
            PKG_CONFIG_LIBDIR='$PKG_CONFIG_LIBDIR'
            CC_FOR_BUILD='$CC_FOR_BUILD'"

        CONFIGURE="$PACKAGE_BSCRIPT_DIR/configure"

        gsed -i 's/cross_compiling=no/cross_compiling=yes/g' "$CONFIGURE"

        if run $CONFIGURE $CONFIGURE_ARGS $@ $CONFIGURE_ENVS ; then
            echo
        else
            # https://docs.github.com/en/actions/learn-github-actions/environment-variables#default-environment-variables
            if [ "$GITHUB_ACTIONS" = true ] ; then
                if [ -f "$PACKAGE_BCACHED_DIR/config.log" ] ; then
                    run cat "$PACKAGE_BCACHED_DIR/config.log"
                elif [ -f "$PACKAGE_BSCRIPT_DIR/config.log" ] ; then
                    run cat "$PACKAGE_BSCRIPT_DIR/config.log"
                fi
            fi
            return 1
        fi
    fi

    if [ "$VERBOSE_GMAKE" = 1 ] ; then
        for Makefile in $(find "$PACKAGE_BSCRIPT_DIR" -name Makefile)
        do
            gsed -i 's|\t@|\t|g'     "$Makefile"
            gsed -i 's|@echo|echo|g' "$Makefile"
        done
        unset Makefile
    fi

    if [ "$CONFIGURE_ONLY" != 1 ] ; then
        gmakew clean
        gmakew
        gmakew install
    fi
}

# gmake wrapper
gmakew() {
    unset GMAKE_OPTIONS
    unset GMAKE_OPTION_SET_C
    unset GMAKE_OPTION_SET_w
    unset GMAKE_OPTION_SET_j

    for option in $@
    do
        case $option in
            -C)           GMAKE_OPTION_SET_C=1 ;;
            -w)           GMAKE_OPTION_SET_w=1 ;;
            -j)           GMAKE_OPTION_SET_j=1 ;;
            -j[1-9])      GMAKE_OPTION_SET_j=1 ;;
            -j[1-9][0-9]) GMAKE_OPTION_SET_j=1 ;;
        esac
    done

    if [ "$GMAKE_OPTION_SET_w" != 1 ] ; then
        GMAKE_OPTIONS="$GMAKE_OPTIONS -w"
    fi

    if [ "$GMAKE_OPTION_SET_C" != 1 ] ; then
        if [ "$PACKAGE_BINBSTD" != 1 ] ; then
            GMAKE_OPTIONS="$GMAKE_OPTIONS -C $PACKAGE_BCACHED_DIR"
        fi
    fi

    if [ "$GMAKE_OPTION_SET_j" != 1 ] ; then
        GMAKE_OPTIONS="$GMAKE_OPTIONS -j$BUILD_NJOBS"
    fi

    if [ "$VERBOSE_GMAKE" = 1 ] ; then
        GMAKE_OPTIONS="$GMAKE_OPTIONS V=1"
    fi

    if [ "$DEBUG_GMAKE" = 1 ] ; then
        GMAKE_OPTIONS="$GMAKE_OPTIONS --debug"
    fi

    if [ "$REQUEST_TO_EXPORT_COMPILE_COMMANDS_JSON" = 1 ] && [ "$BEAR_ENABLED" = 1 ] ; then
        run bear -- $GMAKE $GMAKE_OPTIONS $*
    else
        run         $GMAKE $GMAKE_OPTIONS $*
    fi
}

# cmakew [2] [--targets=<comma-separated list>] [--components=<comma-separated list>] [CMAKE-OPTIONS]
cmakew() {
    unset CMAKE_EXTRA_ARGS
    unset CMAKE_BUILD_TARGETS
    unset CMAKE_INSTALL_COMPONENTS
    unset CMAKE_BUILD_STATIC_SHARED_LIBRARY_SEPARATEDLY

    if [ "$1" = 2 ] ; then
        CMAKE_BUILD_STATIC_SHARED_LIBRARY_SEPARATEDLY=1
        shift
    fi

    while [ -n "$1" ]
    do
        case $1 in
            -S) shift; PACKAGE_BSCRIPT_DIR="$1" ;;
            -B) shift; PACKAGE_BCACHED_DIR="$1" ;;
            --targets=*)
                TARGETS="${1#*=}"

                export IFS=','

                for item in $TARGETS
                do
                    CMAKE_BUILD_TARGETS="$CMAKE_BUILD_TARGETS $item"
                done

                unset IFS
                ;;
            --components=*)
                COMPONENTS="${1#*=}"

                export IFS=','

                for item in $COMPONENTS
                do
                    CMAKE_INSTALL_COMPONENTS="$CMAKE_INSTALL_COMPONENTS $item"
                done

                unset IFS
                ;;
            *)  CMAKE_EXTRA_ARGS="$CMAKE_EXTRA_ARGS $1"
        esac
        shift
    done

    if [ "$CMAKE_BUILD_STATIC_SHARED_LIBRARY_SEPARATEDLY" = 1 ] ; then
        cmakew_internal $CMAKE_EXTRA_ARGS -DBUILD_SHARED_LIBS=OFF
        cmakew_internal $CMAKE_EXTRA_ARGS -DBUILD_SHARED_LIBS=ON
    else
        cmakew_internal $CMAKE_EXTRA_ARGS
    fi
}

# https://cmake.org/cmake/help/latest/manual/cmake-toolchains.7.html#cross-compiling
# https://cmake.org/cmake/help/latest/variable/CMAKE_EXPORT_COMPILE_COMMANDS.html
# https://cmake.org/cmake/help/latest/variable/CMAKE_FIND_ROOT_PATH.html
# https://cmake.org/cmake/help/latest/variable/CMAKE_PREFIX_PATH.html
# https://cmake.org/cmake/help/latest/variable/CMAKE_INSTALL_PREFIX.html
# https://cmake.org/cmake/help/latest/variable/CMAKE_BUILD_TYPE.html
# https://cmake.org/cmake/help/latest/variable/BUILD_SHARED_LIBS.html
# https://cmake.org/cmake/help/latest/command/enable_testing.html?highlight=build_testing
# https://developer.android.com/ndk/guides/cmake
# run in a subshell
cmakew_internal() {
    if [ "$BUILD_FOR_NATIVE" = 1 ] ; then
        CMAKE_CONFIG_OPTIONS="-Wno-dev -DCMAKE_EXPORT_COMPILE_COMMANDS=$CMAKE_EXPORT_COMPILE_COMMANDS -DBUILD_TESTING=OFF"

        # https://cmake.org/cmake/help/latest/variable/CMAKE_FIND_DEBUG_MODE.html
        if [ "$DEBUG_CMAKE" = 1 ] ; then
            CMAKE_CONFIG_OPTIONS="$CMAKE_CONFIG_OPTIONS -DCMAKE_FIND_DEBUG_MODE=TRUE"
        fi

        CMAKE_CONFIG_OPTIONS="$CMAKE_CONFIG_OPTIONS -DBUILD_SHARED_LIBS=OFF -DCMAKE_INSTALL_PREFIX='$PACKAGE_INSTALL_DIR' -S $PACKAGE_BSCRIPT_DIR -B $PACKAGE_BCACHED_DIR"

        run $CMAKE $CMAKE_CONFIG_OPTIONS $@ &&
        run $CMAKE --build   "$PACKAGE_BCACHED_DIR" -- -j$BUILD_NJOBS &&
        run $CMAKE --install "$PACKAGE_BCACHED_DIR"
    else
        unset CMAKE_PROJECT_INCLUDE

        if [ "$PACKAGE_CREATE_FULLY_STATICALLY_LINKED_EXECUTABLE" = 1 ] || [ "$PACKAGE_CREATE_MOSTLY_STATICALLY_LINKED_EXECUTABLE" = 1 ] ; then
            # https://cmake.org/cmake/help/latest/variable/CMAKE_PROJECT_INCLUDE.html
            CMAKE_PROJECT_INCLUDE="$PACKAGE_WORKING_DIR/project-after.cmake"

            # https://cmake.org/cmake/help/latest/variable/CMAKE_FIND_LIBRARY_SUFFIXES.html
            if [ "$PACKAGE_CREATE_FULLY_STATICALLY_LINKED_EXECUTABLE" = 1 ] ; then
                printf 'set(CMAKE_FIND_LIBRARY_SUFFIXES ".a")\n'       > "$CMAKE_PROJECT_INCLUDE"
            else
                printf 'set(CMAKE_FIND_LIBRARY_SUFFIXES ".a" ".so")\n' > "$CMAKE_PROJECT_INCLUDE"
            fi

            if [ "$VERBOSE_CMAKE" = 1 ] ; then
                run cat "$CMAKE_PROJECT_INCLUDE"
            fi
        fi

        case $PROFILE in
            debug)   CMAKE_BUILD_TYPE=Debug   ;;
            release) CMAKE_BUILD_TYPE=Release ;;
        esac

        if [ "$VERBOSE_CMAKE" = 1 ] ; then
            CMAKE_VERBOSE_MAKEFILE=ON
            CMAKE_COLOR_MAKEFILE=ON
        else
            CMAKE_VERBOSE_MAKEFILE=OFF
            CMAKE_COLOR_MAKEFILE=OFF
        fi

        # https://cmake.org/cmake/help/latest/variable/CMAKE_FIND_DEBUG_MODE.html
        if [ "$DEBUG_CMAKE" = 1 ] ; then
            CMAKE_FIND_DEBUG_MODE=ON
        else
            CMAKE_FIND_DEBUG_MODE=OFF
        fi

        case $TARGET_PLATFORM_ARCH in
            armv7a)  CMAKE_SYSTEM_PROCESSOR=armv7-a ;;
            aarch64) CMAKE_SYSTEM_PROCESSOR=aarch64 ;;
            i686)    CMAKE_SYSTEM_PROCESSOR=i686    ;;
            x86_64)  CMAKE_SYSTEM_PROCESSOR=x86_64  ;;
        esac

        CMAKE_TOOLCHAIN_FILE="$PACKAGE_WORKING_DIR/android.toolchain.cmake"

        cat > "$CMAKE_TOOLCHAIN_FILE" <<EOF
message(STATUS "CMake command: \${CMAKE_COMMAND}")
message(STATUS "CMake version: \${CMAKE_VERSION}")

if ("\${BUILD_SHARED_LIBS}" STREQUAL "")
    set(BUILD_SHARED_LIBS Release)
endif()

set(ANDROID_ABI "${TARGET_PLATFORM_ABI}")
set(ANDROID_PLATFORM "android-${TARGET_PLATFORM_VERS}")
set(ANDROID_TOOLCHAIN clang)
set(ANDROID_ARM_NEON TRUE)
set(ANDROID_STL c++_shared)
include(${ANDROID_NDK_HOME}/build/cmake/android.toolchain.cmake)

message(STATUS "CMAKE_HOST_SYSTEM_NAME: \${CMAKE_HOST_SYSTEM_NAME}")
message(STATUS "     CMAKE_SYSTEM_NAME: \${CMAKE_SYSTEM_NAME}")

set(CMAKE_BUILD_TYPE  $CMAKE_BUILD_TYPE)

set(CMAKE_C_COMPILER "$CC")
set(CMAKE_C_FLAGS "$CPPFLAGS $CFLAGS")

set(CMAKE_CXX_COMPILER "$CXX")
set(CMAKE_CXX_FLAGS "$CPPFLAGS $CXXFLAGS")

set(CMAKE_ASM_COMPILER "$CC")

set(CMAKE_SHARED_LINKER_FLAGS "$LDFLAGS")
set(CMAKE_EXE_LINKER_FLAGS    "$LDFLAGS")

set(CMAKE_C_COMPILER_AR     "$AR")
set(CMAKE_C_COMPILER_RANLIB "$RANLIB")

set(CMAKE_CXX_COMPILER_AR     "$AR")
set(CMAKE_CXX_COMPILER_RANLIB "$RANLIB")

set(CMAKE_AR      "$AR")
set(CMAKE_RANLIB  "$RANLIB")

set(CMAKE_LINKER  "$LD")

set(CMAKE_NM      "$NM")
set(CMAKE_READELF "$READELF")

set(CMAKE_OBJCOPY "$OBJCOPY")
set(CMAKE_OBJDUMP "$OBJDUMP")

set(CMAKE_STRIP   "$STRIP")

set(CMAKE_ADDR2LINE "$ADDR2LINE")

if ("\${CMAKE_EXE_LINKER_FLAGS}" MATCHES ".*-static.*")
    set(CMAKE_SKIP_INSTALL_RPATH ON)
endif()

set(CMAKE_FIND_DEBUG_MODE $CMAKE_FIND_DEBUG_MODE)
set(CMAKE_FIND_ROOT_PATH "$CMAKE_FIND_ROOT_PATH")
set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)

set(CMAKE_INSTALL_MESSAGE "$CMAKE_INSTALL_MESSAGE")
EOF

        NASM="$(command -v nasm || command -v yasm || true)"

        if [ -n "$NASM" ] ; then
            cat >> "$CMAKE_TOOLCHAIN_FILE" <<EOF
set(CMAKE_ASM_NASM_COMPILER "$NASM")
EOF
        fi

        if [ "$ENABLE_CCACHE" = 1 ] ; then
            cat >> "$CMAKE_TOOLCHAIN_FILE" <<EOF
set(NDK_CCACHE "$CCACHE")
EOF
        fi

        if [ "$VERBOSE_CMAKE" = 1 ] ; then
            bat --language=cmake --paging=never "$CMAKE_TOOLCHAIN_FILE"
        fi

        if [   -f "$PACKAGE_BCACHED_DIR/CMakeCache.txt" ] ; then
            rm -f "$PACKAGE_BCACHED_DIR/CMakeCache.txt"
        fi

        CMAKE_CONFIG_OPTIONS="-Wno-dev -DBUILD_TESTING=OFF -DCMAKE_INSTALL_LIBDIR=lib -DCMAKE_INSTALL_PREFIX='$PACKAGE_INSTALL_DIR' -DCMAKE_TOOLCHAIN_FILE='$CMAKE_TOOLCHAIN_FILE' -DCMAKE_VERBOSE_MAKEFILE='$CMAKE_VERBOSE_MAKEFILE' -DCMAKE_COLOR_MAKEFILE='$CMAKE_COLOR_MAKEFILE'"

        if [ -n "$CMAKE_PROJECT_INCLUDE" ] && [ -f "$CMAKE_PROJECT_INCLUDE" ] ; then
            CMAKE_CONFIG_OPTIONS="$CMAKE_CONFIG_OPTIONS -DCMAKE_PROJECT_INCLUDE=$CMAKE_PROJECT_INCLUDE"
        fi

        run "$CMAKE" "$CMAKE_CONFIG_OPTIONS" -S "$PACKAGE_BSCRIPT_DIR" -B "$PACKAGE_BCACHED_DIR" "$@"

        if [ -z "$CMAKE_BUILD_TARGETS" ] ; then
            run "$CMAKE" --build   "$PACKAGE_BCACHED_DIR"
        else
            run "$CMAKE" --build   "$PACKAGE_BCACHED_DIR" --target "$CMAKE_BUILD_TARGETS"
        fi

        if [ -z "$CMAKE_INSTALL_COMPONENTS" ] ; then
            run "$CMAKE" --install "$PACKAGE_BCACHED_DIR"
        else
            for component in $CMAKE_INSTALL_COMPONENTS
            do
            run "$CMAKE" --install "$PACKAGE_BCACHED_DIR" --component "$component"
            done
        fi
    fi
}

# https://github.com/xmake-io/xmake/issues/2003
# run in a subshell
xmakew() {
    XMAKE_CONFIG_OPTIONS="$@"

    XMAKE_CONFIG_OPTION_CLEAN=
    XMAKE_CONFIG_OPTION_MODE=
    XMAKE_CONFIG_OPTION_vD=

    for arg in $@
    do
        case $arg in
            -c|--clean)  XMAKE_CONFIG_OPTION_CLEAN=set ;;
            -m|--mode=*) XMAKE_CONFIG_OPTION_MODE=set  ;;
            -vD)         XMAKE_CONFIG_OPTION_vD=set ;;
        esac
    done

    if [ "$DEBUG_XMAKE" = 1 ] && [ -z "$XMAKE_CONFIG_OPTION_vD" ] ; then
        XMAKE_CONFIG_OPTIONS="$XMAKE_CONFIG_OPTION_vD -vD"
    fi

    if [ -z "$XMAKE_CONFIG_OPTION_CLEAN" ] ; then
        XMAKE_CONFIG_OPTIONS="$XMAKE_CONFIG_OPTIONS --clean"
    fi

    if [ -z "$XMAKE_CONFIG_OPTION_MODE" ] ; then
        XMAKE_CONFIG_OPTIONS="$XMAKE_CONFIG_OPTIONS --mode=$PROFILE"
    fi

    if [ "$BUILD_FOR_NATIVE" = 1 ] ; then
        run $XMAKE config $XMAKE_CONFIG_OPTIONS --project=$PACKAGE_BSCRIPT_DIR --buildir=$PACKAGE_BCACHED_DIR &&
        run $XMAKE --jobs=$BUILD_NJOBS &&
        run $XMAKE install -o "$PACKAGE_INSTALL_DIR"
    else
        XMAKE_CONFIG_OPTIONS="$XMAKE_CONFIG_OPTIONS --plat=android --arch=$TARGET_PLATFORM_ABI --ndk_sdkver=$TARGET_PLATFORM_VERS --toolchain=ndk --ndk=$ANDROID_NDK_HOME --buildir=$PACKAGE_BCACHED_DIR --cc=$CC --cxx=$CXX --cflags='$CFLAGS $CPPFLAGS' --cxxflags='$CXXFLAGS $CPPFLAGS' --ldflags='$LDFLAGS' --shflags='$LDFLAGS'"

        run $XMAKE config $XMAKE_CONFIG_OPTIONS &&
        run $XMAKE --jobs=$BUILD_NJOBS &&
        run $XMAKE install -o "$PACKAGE_INSTALL_DIR"
    fi
}

# https://mesonbuild.com/Cross-compilation.html
# run in a subshell
mesonw() {
    case $TARGET_PLATFORM_ARCH in
        armv7a)
            HOST_MACHINE_CPU_FAMILY='arm'
            HOST_MACHINE_CPU_NAME="$TARGET_PLATFORM_ARCH"
            ;;
        aarch64)
            HOST_MACHINE_CPU_FAMILY='aarch64'
            HOST_MACHINE_CPU_NAME='armv8a'
            ;;
        i686)
            HOST_MACHINE_CPU_FAMILY='x86'
            HOST_MACHINE_CPU_NAME="$TARGET_PLATFORM_ARCH"
            ;;
        x86_64)
            HOST_MACHINE_CPU_FAMILY='x86_64'
            HOST_MACHINE_CPU_NAME="$TARGET_PLATFORM_ARCH"
            ;;
    esac

    MESON_CROSS_FILE="$PACKAGE_BCACHED_DIR/cross-file"

    cat > "$MESON_CROSS_FILE" <<EOF
[host_machine]
system = 'android'
endian = 'little'
cpu_family = '$HOST_MACHINE_CPU_FAMILY'
cpu = '$HOST_MACHINE_CPU_NAME'

[binaries]
c = '$CC'
cpp = '$CXX'
ar = '$AR'
strip = '$STRIP'
cmake = '$CMAKE'
pkg-config = '$PKG_CONFIG'

[built-in options]
c_args = $(to_meson_array $CFLAGS $CPPFLAGS)
c_link_args = $(to_meson_array $LDFLAGS)
cpp_args = $(to_meson_array $CXXFLAGS $CPPFLAGS)
cpp_link_args = $(to_meson_array $LDFLAGS)
EOF

    MESON_SETUP_ARGS="--prefix=$PACKAGE_INSTALL_DIR --buildtype=$PROFILE --backend=ninja --pkg-config-path=$PKG_CONFIG_PATH --build.pkg-config-path=$PKG_CONFIG_PATH_FOR_BUILD --cross-file=$MESON_CROSS_FILE -Dlibdir=lib"

    if [ "$PACKAGE_CREATE_FULLY_STATICALLY_LINKED_EXECUTABLE" = 1 ] || [ "$PACKAGE_CREATE_MOSTLY_STATICALLY_LINKED_EXECUTABLE" = 1 ] ; then
        MESON_SETUP_ARGS="$MESON_SETUP_ARGS -Ddefault_library=static --prefer-static"
    else
        MESON_SETUP_ARGS="$MESON_SETUP_ARGS -Ddefault_library=both"
    fi

    MESON_COMPILE_ARGS="-C $PACKAGE_BCACHED_DIR -j $BUILD_NJOBS"
    MESON_INSTALL_ARGS="-C $PACKAGE_BCACHED_DIR"

    if [ "$VERBOSE_MESON" = 1 ] ; then
        MESON_COMPILE_ARGS="$MESON_COMPILE_ARGS -v"
    fi

    run "$MESON" setup   "$MESON_SETUP_ARGS" "$@" "$PACKAGE_BCACHED_DIR" "$PACKAGE_BSCRIPT_DIR" &&
    run "$MESON" compile "$MESON_COMPILE_ARGS" &&
    run "$MESON" install "$MESON_INSTALL_ARGS"
}

to_meson_array() {
    RESULT=

    for item in "$@"
    do
        if [ -z "$RESULT" ] ; then
            RESULT="'$item'"
        else
            RESULT="$RESULT, '$item'"
        fi
    done

    printf '[%s]\n' "$RESULT"
}

# https://developer.android.com/ndk/guides/ndk-build
ndk_build() {
    # https://developer.android.com/ndk/downloads/revision_history#expandable-33
    # Android NDK r7 (November 2011)
    if [ "$ENABLE_CCACHE" = 1 ] ; then
        export NDK_CCACHE=$CCACHE
    fi

    NDK_BUILD_ARGS="NDK_PROJECT_PATH=. APP_BUILD_SCRIPT=Android.mk APP_PLATFORM=android-$TARGET_PLATFORM_VERS APP_STRIP_MODE=-S"

    case $PROFILE in
        debug)   NDK_BUILD_ARGS="$NDK_BUILD_ARGS NDK_DEBUG=1" ;;
        release) NDK_BUILD_ARGS="$NDK_BUILD_ARGS NDK_DEBUG=0" ;;
    esac

    if [ "$REQUEST_TO_EXPORT_COMPILE_COMMANDS_JSON" = 1 ] ; then
        NDK_BUILD_ARGS="$NDK_BUILD_ARGS GEN_COMPILE_COMMANDS_DB=true"
    fi

    if [ "$LOG_LEVEL" -ge "$LOG_LEVEL_VERBOSE" ] ; then
        NDK_BUILD_ARGS="$NDK_BUILD_ARGS V=1"
    fi

    if [ "$LOG_LEVEL" -ge "$LOG_LEVEL_VERY_VERBOSE" ] ; then
        NDK_BUILD_ARGS="$NDK_BUILD_ARGS NDK_LOG=1"
    fi

    run ndk-build $NDK_BUILD_ARGS
}

########################################################################

inspect_android_ndk_info() {
    [ -z "$1" ] && abort 1 "$NDKPKG_ARG0 ndkinfo <ANDROID-NDK-HOME> , <ANDROID-NDK-HOME> is not given."
    [ -d "$1" ] || abort 1 "'$1' was expected to be a directory, but it was not."

    NDK_SOURCE_PROPERTIES_FILEPATH="$1/source.properties"

    [ -e "$NDK_SOURCE_PROPERTIES_FILEPATH" ] || abort 1 "'$NDK_SOURCE_PROPERTIES_FILEPATH' was expected to be exist, but it was not."
    [ -f "$NDK_SOURCE_PROPERTIES_FILEPATH" ] || abort 1 "'$NDK_SOURCE_PROPERTIES_FILEPATH' was expected to be a regular file, but it was not."

    ANDROID_CMAKE_TOOLCHAIN_FILE="$1/build/cmake/android.toolchain.cmake"

    [ -e "$ANDROID_CMAKE_TOOLCHAIN_FILE" ] || abort 1 "'$ANDROID_CMAKE_TOOLCHAIN_FILE' was expected to be exist, but it was not."
    [ -f "$ANDROID_CMAKE_TOOLCHAIN_FILE" ] || abort 1 "'$ANDROID_CMAKE_TOOLCHAIN_FILE' was expected to be a regular file, but it was not."

    ANDROID_NDK_VERSION=
    ANDROID_NDK_VERSION_MAJOR=

    ANDROID_NDK_VERSION="$(sed -n '/Pkg.Revision/p' "$NDK_SOURCE_PROPERTIES_FILEPATH" | sed  's/Pkg\.Revision = \(.*\).*/\1/')"

    if [ -z "$ANDROID_NDK_VERSION" ] ; then
        abort 1 "no Pkg.Revision property in $NDK_SOURCE_PROPERTIES_FILEPATH"
    fi

    ANDROID_NDK_VERSION_MAJOR="$(printf '%s\n' "$ANDROID_NDK_VERSION" | cut -d. -f1)"

    if [ "$NATIVE_PLATFORM_KIND" = darwin ] ; then
        ANDROID_NDK_TOOLCHAIN_HOST_TAG='darwin-x86_64'
    else
        ANDROID_NDK_TOOLCHAIN_HOST_TAG="linux-$NATIVE_PLATFORM_ARCH"
    fi

    ANDROID_NDK_TOOLCHAIN_ROOT="$1/toolchains/llvm/prebuilt/$ANDROID_NDK_TOOLCHAIN_HOST_TAG"

    [ -e "$ANDROID_NDK_TOOLCHAIN_ROOT" ] || abort 1 "'$ANDROID_NDK_TOOLCHAIN_ROOT' was expected to be exist, but it was not."
    [ -d "$ANDROID_NDK_TOOLCHAIN_ROOT" ] || abort 1 "'$ANDROID_NDK_TOOLCHAIN_ROOT' was expected to be a directory, but it was not."

    ANDROID_NDK_TOOLCHAIN_BIND="$ANDROID_NDK_TOOLCHAIN_ROOT/bin"

    [ -e "$ANDROID_NDK_TOOLCHAIN_BIND" ] || abort 1 "'$ANDROID_NDK_TOOLCHAIN_BIND' was expected to be exist, but it was not."
    [ -d "$ANDROID_NDK_TOOLCHAIN_BIND" ] || abort 1 "'$ANDROID_NDK_TOOLCHAIN_BIND' was expected to be a directory, but it was not."

    ANDROID_NDK_SYSROOT="$ANDROID_NDK_TOOLCHAIN_ROOT/sysroot"

    [ -e "$ANDROID_NDK_SYSROOT" ] || abort 1 "'$ANDROID_NDK_SYSROOT' was expected to be exist, but it was not."
    [ -d "$ANDROID_NDK_SYSROOT" ] || abort 1 "'$ANDROID_NDK_SYSROOT' was expected to be a directory, but it was not."

    #########################################################################################

    ANDROID_NDK_CC="$ANDROID_NDK_TOOLCHAIN_BIND/clang"
    ANDROID_NDK_CXX="$ANDROID_NDK_TOOLCHAIN_BIND/clang++"
    ANDROID_NDK_CPP="$ANDROID_NDK_CC -E"

    # https://github.com/android/ndk/wiki/Changelog-r22
    # https://github.com/android/ndk/wiki/Changelog-r23
    if [ "$ANDROID_NDK_VERSION_MAJOR" -ge 22 ] ; then
        ANDROID_NDK_LD="$ANDROID_NDK_TOOLCHAIN_BIND/ld.lld"
        ANDROID_NDK_AS="$ANDROID_NDK_TOOLCHAIN_BIND/llvm-as"
        ANDROID_NDK_AR="$ANDROID_NDK_TOOLCHAIN_BIND/llvm-ar"
        ANDROID_NDK_NM="$ANDROID_NDK_TOOLCHAIN_BIND/llvm-nm"
        ANDROID_NDK_SIZE="$ANDROID_NDK_TOOLCHAIN_BIND/llvm-size"
        ANDROID_NDK_STRIP="$ANDROID_NDK_TOOLCHAIN_BIND/llvm-strip"
        ANDROID_NDK_RANLIB="$ANDROID_NDK_TOOLCHAIN_BIND/llvm-ranlib"
        ANDROID_NDK_STRINGS="$ANDROID_NDK_TOOLCHAIN_BIND/llvm-strings"
        ANDROID_NDK_OBJDUMP="$ANDROID_NDK_TOOLCHAIN_BIND/llvm-objdump"
        ANDROID_NDK_OBJCOPY="$ANDROID_NDK_TOOLCHAIN_BIND/llvm-objcopy"
        ANDROID_NDK_READELF="$ANDROID_NDK_TOOLCHAIN_BIND/llvm-readelf"
    else
        ANDROID_NDK_LD="$ANDROID_NDK_TOOLCHAIN_BIND/aarch64-linux-android-ld"
        ANDROID_NDK_AS="$ANDROID_NDK_TOOLCHAIN_BIND/aarch64-linux-android-as"
        ANDROID_NDK_AR="$ANDROID_NDK_TOOLCHAIN_BIND/aarch64-linux-android-ar"
        ANDROID_NDK_NM="$ANDROID_NDK_TOOLCHAIN_BIND/aarch64-linux-android-nm"
        ANDROID_NDK_SIZE="$ANDROID_NDK_TOOLCHAIN_BIND/aarch64-linux-android-size"
        ANDROID_NDK_STRIP="$ANDROID_NDK_TOOLCHAIN_BIND/aarch64-linux-android-strip"
        ANDROID_NDK_RANLIB="$ANDROID_NDK_TOOLCHAIN_BIND/aarch64-linux-android-ranlib"
        ANDROID_NDK_STRINGS="$ANDROID_NDK_TOOLCHAIN_BIND/aarch64-linux-android-strings"
        ANDROID_NDK_OBJDUMP="$ANDROID_NDK_TOOLCHAIN_BIND/aarch64-linux-android-objdump"
        ANDROID_NDK_OBJCOPY="$ANDROID_NDK_TOOLCHAIN_BIND/aarch64-linux-android-objcopy"
        ANDROID_NDK_READELF="$ANDROID_NDK_TOOLCHAIN_BIND/aarch64-linux-android-readelf"
    fi

    #########################################################################################

    ANDROID_NDK_SUPPORTED_SDK_API_LEVEL_ALL="$(ls "$ANDROID_NDK_TOOLCHAIN_BIND" | sed -n '/aarch64-linux-android[1-9][0-9]-clang++/p' | cut -d- -f3 | sed 's/android//')"
    ANDROID_NDK_SUPPORTED_MIN_SDK_API_LEVEL="$(printf '%s\n' "$ANDROID_NDK_SUPPORTED_SDK_API_LEVEL_ALL" | sort | head -n 1)"
    ANDROID_NDK_SUPPORTED_MAX_SDK_API_LEVEL="$(printf '%s\n' "$ANDROID_NDK_SUPPORTED_SDK_API_LEVEL_ALL" | sort | tail -n 1)"

    #########################################################################################

    ANDROID_NDK_HOME="$1"
    ANDROID_NDK_ROOT="$1"
}

println_android_ndk_info() {
    cat <<EOF
ANDROID_NDK_HOME='$ANDROID_NDK_HOME'
ANDROID_NDK_ROOT='$ANDROID_NDK_ROOT'
ANDROID_NDK_REVISION='$ANDROID_NDK_REVISION'
ANDROID_NDK_VERSION='$ANDROID_NDK_VERSION'
ANDROID_NDK_VERSION_MAJOR='$ANDROID_NDK_VERSION_MAJOR'
ANDROID_NDK_TOOLCHAIN_ROOT='$ANDROID_NDK_TOOLCHAIN_ROOT'
ANDROID_NDK_TOOLCHAIN_BIND='$ANDROID_NDK_TOOLCHAIN_BIND'
ANDROID_NDK_SYSROOT='$ANDROID_NDK_SYSROOT'
ANDROID_NDK_CC='$ANDROID_NDK_CC'
ANDROID_NDK_CXX='$ANDROID_NDK_CXX'
ANDROID_NDK_CPP='$ANDROID_NDK_CPP'
ANDROID_NDK_LD='$ANDROID_NDK_LD'
ANDROID_NDK_AS='$ANDROID_NDK_AS'
ANDROID_NDK_AR='$ANDROID_NDK_AR'
ANDROID_NDK_NM='$ANDROID_NDK_NM'
ANDROID_NDK_SIZE='$ANDROID_NDK_SIZE'
ANDROID_NDK_STRIP='$ANDROID_NDK_STRIP'
ANDROID_NDK_RANLIB='$ANDROID_NDK_RANLIB'
ANDROID_NDK_STRINGS='$ANDROID_NDK_STRINGS'
ANDROID_NDK_OBJDUMP='$ANDROID_NDK_OBJDUMP'
ANDROID_NDK_OBJCOPY='$ANDROID_NDK_OBJCOPY'
ANDROID_NDK_READELF='$ANDROID_NDK_READELF'
ANDROID_NDK_SUPPORTED_MIN_SDK_API_LEVEL='$ANDROID_NDK_SUPPORTED_MIN_SDK_API_LEVEL'
ANDROID_NDK_SUPPORTED_MAX_SDK_API_LEVEL='$ANDROID_NDK_SUPPORTED_MAX_SDK_API_LEVEL'
EOF
}

# install_android_ndk_if_needed <ANDROID_NDK_REVISION>
  install_android_ndk_if_needed() {
    ANDROID_NDK_PKG="android-ndk-r$1"

    "$UPPM" is-installed "$ANDROID_NDK_PKG" || {
        note "Installing $ANDROID_NDK_PKG via uppm"
        uppm about
        uppm update
        uppm install "$ANDROID_NDK_PKG"
    }

    ANDROID_NDK_HOME="$UPPM_HOME/installed/$ANDROID_NDK_PKG"
    ANDROID_NDK_REVISION="$1"

    #if [ "$NATIVE_PLATFORM_KIND" = darwin ] ; then
    #    ANDROID_NDK_TOOLCHAIN_HOST_TAG='darwin-x86_64'
    #else
    #    ANDROID_NDK_TOOLCHAIN_HOST_TAG="linux-$NATIVE_PLATFORM_ARCH"
    #fi

    # https://github.com/termux/termux-packages/issues/21113
    # https://github.com/termux/termux-packages/blob/master/ndk-patches/27c/time.h.patch
    # gsed -i -e '41c #if __ANDROID_API__ >= 35' -e '53c #endif' "$ANDROID_NDK_HOME/toolchains/llvm/prebuilt/$ANDROID_NDK_TOOLCHAIN_HOST_TAG/sysroot/usr/include/time.h"
}

# setup_android_ndk_env [ANDROID_NDK_REVISION] [ANDROID_NDK_HOME]
  setup_android_ndk_env() {
    if [ -z "$1" ] ; then
        if [ -z "$2" ] ; then
            if [ "$NATIVE_PLATFORM_KIND" = android ] ; then
                # use comunity compiled Android NDK for aarch64-linux right now, I might compile my own at some point.
                # https://github.com/lzhiyong/termux-ndk/releases/tag/android-ndk
                install_android_ndk_if_needed 27b
            else
                install_android_ndk_if_needed 27d
            fi
        else
            install_android_ndk_if_needed '' "$2"
        fi
    else
        install_android_ndk_if_needed "$1"
    fi

    inspect_android_ndk_info "$ANDROID_NDK_HOME"

    if [ "$DUMP_NDK" = 1 ] ; then
        println_android_ndk_info
    fi

    export ANDROID_NDK_HOME
    export ANDROID_NDK_ROOT
}

# }}}
##############################################################################
# {{{ ndk-pkg setup

__setup() {
    unset REQUEST_TO_INSTALL_CURL_VIA_SYSTEM_PACKAGE_MANAGER

    if [ "$1" = -y ] ; then
        REQUEST_TO_INSTALL_CURL_VIA_SYSTEM_PACKAGE_MANAGER=1
    fi

    unset NATIVE_PLATFORM_KIND
    unset NATIVE_PLATFORM_ARCH
    unset NATIVE_PLATFORM_VERS

    __setup_Darwin() {
        NATIVE_PLATFORM_ARCH="$(uname -m)"

        NATIVE_PLATFORM_VERS_MAJOR="$(sw_vers -productVersion | cut -d. -f1)"

        if [ "$NATIVE_PLATFORM_VERS_MAJOR" -le 10 ] ; then
            NATIVE_PLATFORM_VERS='10.15'
        elif [ "$NATIVE_PLATFORM_VERS_MAJOR" -ge 15 ] ; then
            NATIVE_PLATFORM_VERS='15.0'
            export UPPM_FORMULA_REPO_URL_OFFICIAL_CORE="https://github.com/leleliu008/uppm-package-repository-macos-15.0-$NATIVE_PLATFORM_ARCH"
        else
            NATIVE_PLATFORM_VERS="$NATIVE_PLATFORM_VERS_MAJOR.0"
        fi

        NATIVE_PLATFORM_TRIPLE="macos-$NATIVE_PLATFORM_VERS-$NATIVE_PLATFORM_ARCH"
    }

    __setup_Linux() {
        if [ "$(uname -o 2>/dev/null || true)" = Android ] ; then
            NATIVE_PLATFORM_VERS="$(getprop ro.build.version.sdk)"
            NATIVE_PLATFORM_TRIPLE="android-$NATIVE_PLATFORM_VERS-arm64-v8a"

            if command -v termux-info > /dev/null && command -v pkg > /dev/null ; then
                TERMUX=1
                export CURLOPT_DNS_SERVERS='8.8.8.8,1.1.1.1'
                export UPPM_FORMULA_REPO_URL_OFFICIAL_CORE="https://github.com/leleliu008/uppm-package-repository-android-$NATIVE_PLATFORM_VERS-aarch64"
            fi
        else
            NATIVE_PLATFORM_ARCH="$(uname -m)"
            NATIVE_PLATFORM_TRIPLE="linux-$NATIVE_PLATFORM_ARCH"

            for FETCH_TOOL in curl wget http lynx aria2c axel
            do
                if command -v "$FETCH_TOOL" > /dev/null ; then
                    break
                else
                    unset FETCH_TOOL
                fi
            done

            if [ -z "$FETCH_TOOL" ] ; then
                if [ "$REQUEST_TO_INSTALL_CURL_VIA_SYSTEM_PACKAGE_MANAGER" = 1 ] ; then
                    __install_curl_via_syspm_on_debian() {
                        apt-get -y update
                        apt-get -y install curl
                    }

                    __install_curl_via_syspm_on_ubuntu() {
                        apt-get -y update
                        apt-get -y install curl
                    }

                    __install_curl_via_syspm_on_linuxmint() {
                        apt-get -y update
                        apt-get -y install curl
                    }

                    __install_curl_via_syspm_on_rocky() {
                        dnf -y update
                        dnf -y install curl
                    }

                    __install_curl_via_syspm_on_almalinux() {
                        dnf -y update
                        dnf -y install curl
                    }

                    __install_curl_via_syspm_on_centos() {
                        dnf -y update
                        dnf -y install curl
                    }

                    __install_curl_via_syspm_on_fedora() {
                        dnf -y update
                        dnf -y install curl
                    }

                    __install_curl_via_syspm_on_rhel() {
                        dnf -y update
                        dnf -y install curl
                    }

                    __install_curl_via_syspm_on_opensuse_leap() {
                        zypper update  -y
                        zypper install -y curl
                    }

                    __install_curl_via_syspm_on_gentoo() {
                        emerge net-misc/curl
                    }

                    __install_curl_via_syspm_on_manjaro() {
                        pacman -Syyuu --noconfirm
                        pacman -S     --noconfirm curl
                    }

                    __install_curl_via_syspm_on_arch() {
                        pacman -Syyuu --noconfirm
                        pacman -S     --noconfirm curl
                    }

                    __install_curl_via_syspm_on_void() {
                        xbps-install -Syu xbps
                        xbps-install -S
                        xbps-install -Syu curl
                    }

                    __install_curl_via_syspm_on_alpine() {
                        apk update
                        apk add curl
                    }

                    if [ -f /etc/os-release ] ; then
                        .   /etc/os-release

                        unset sudo

                        if [ "$(id -u)" -ne 0 ] ; then
                            sudo=sudo
                        fi

                        if [ "$ID" = 'opensuse-leap' ] ; then
                            ID='opensuse_leap'
                        fi

                        $sudo __install_curl_via_syspm_on_$ID

                        FETCH_TOOL=curl
                    else
                        abort 1 "/etc/os-release file does not exist, ndk-pkg can not determine what is your host system and how to install curl package."
                    fi

                    if [ -z "$FETCH_TOOL" ] ; then
                        abort 1 "none of curl wget http lynx aria2c axel command was found, please install one of them then try again."
                    fi
                fi
            fi
        fi
    }

    unset TERMUX

    NATIVE_PLATFORM_KIND="$(uname -s)"

    __setup_$NATIVE_PLATFORM_KIND

    ##################################################################################

    SESSION_DIR="$NDKPKG_HOME/run/$$/core"

    run rm -rf     "$SESSION_DIR"
    run install -d "$SESSION_DIR"
    run cd         "$SESSION_DIR"

    ##################################################################################

    BSDTAR="$(command -v bsdtar || true)"

    if [ -n "$BSDTAR" ] ; then
        TAR="$BSDTAR"
    else
        TAR="$(command -v gtar || command -v tar || true)"
        XZ="$(command -v xz || true)"

        if [ -z "$TAR" ] || [ -z "$XZ" ] ; then
            wfetch 'https://github.com/leleliu008/bsdtar.exe/releases/download/2024.10.03/bsdtar-3.7.4-linux-x86_64.exe' -o bsdtar --no-buffer
            chmod +x bsdtar
            TAR=./bsdtar
        fi
    fi

    ##################################################################################

    # https://curl.se/docs/caextract.html
    wfetch 'https://curl.se/ca/cacert.pem' --no-buffer

    export SSL_CERT_FILE="$PWD/cacert.pem"

    ##################################################################################

    wfetch 'https://raw.githubusercontent.com/leleliu008/ndk-pkg/master/ndk-pkg-core-latest-release-version' --no-buffer

    NDKPKG_CORE_LATEST_RELEASE_VERSION="$(cat ndk-pkg-core-latest-release-version)"
    NDKPKG_CORE_LATEST_RELEASE_TAG="ndk-pkg-core-$NDKPKG_CORE_LATEST_RELEASE_VERSION"
    NDKPKG_CORE_LATEST_RELEASE_TARBALL_FILENAME="$NDKPKG_CORE_LATEST_RELEASE_TAG-$NATIVE_PLATFORM_TRIPLE.tar.xz"
    NDKPKG_CORE_LATEST_RELEASE_TARBALL_URL="https://github.com/leleliu008/ndk-pkg/releases/download/$NDKPKG_CORE_LATEST_RELEASE_TAG/$NDKPKG_CORE_LATEST_RELEASE_TARBALL_FILENAME"

    wfetch "$NDKPKG_CORE_LATEST_RELEASE_TARBALL_URL" --no-buffer

    run $TAR xvf "$NDKPKG_CORE_LATEST_RELEASE_TARBALL_FILENAME" --strip-components=1 --no-same-owner

    ##################################################################################

    run ln -s ../wrapper-native-cc  bin/cc
    run ln -s ../wrapper-native-c++ bin/c++

    ##################################################################################

    run ./uppm about
    run ./uppm update

    unset UPPM_PACKAGE_EXEFIND_PATH
    unset UPPM_PACKAGE_ACLOCAL_PATH

    unset EXTRA_UPPM_PACKAGE_NAME

    if [ "$TERMUX" != 1 ] ; then
        EXTRA_UPPM_PACKAGE_NAME=coreutils
    fi

    for UPPM_PACKAGE_NAME in bash $EXTRA_UPPM_PACKAGE_NAME findutils gawk gsed grep bsdtar zip git curl tree patchelf xxd fzf bat jq yq d2 dot_static
    do
        run ./uppm install "$UPPM_PACKAGE_NAME"

        UPPM_PACKAGE_INSTALLED_DIR="$UPPM_HOME/installed/$UPPM_PACKAGE_NAME"

        if [ -d "$UPPM_PACKAGE_INSTALLED_DIR/bin" ] ; then
            UPPM_PACKAGE_EXEFIND_PATH="$UPPM_PACKAGE_EXEFIND_PATH:$UPPM_PACKAGE_INSTALLED_DIR/bin"
        fi

        if [ -d "$UPPM_PACKAGE_INSTALLED_DIR/sbin" ] ; then
            UPPM_PACKAGE_EXEFIND_PATH="$UPPM_PACKAGE_EXEFIND_PATH:$UPPM_PACKAGE_INSTALLED_DIR/sbin"
        fi

        if [ -d "$UPPM_PACKAGE_INSTALLED_DIR/share/aclocal" ] ; then
            UPPM_PACKAGE_ACLOCAL_PATH="$UPPM_PACKAGE_ACLOCAL_PATH:$UPPM_PACKAGE_INSTALLED_DIR/share/aclocal"
        fi
    done

    UPPM_PACKAGE_EXEFIND_PATH="${UPPM_PACKAGE_EXEFIND_PATH#':'}"
    UPPM_PACKAGE_ACLOCAL_PATH="${UPPM_PACKAGE_ACLOCAL_PATH#':'}"

    ##################################################################################

    cat > init.sh <<EOF
export ACLOCAL_PATH="$UPPM_PACKAGE_ACLOCAL_PATH:\$ACLOCAL_PATH"
export PATH="$UPPM_PACKAGE_EXEFIND_PATH:\$PATH"

# https://git-scm.com/book/en/v2/Git-Internals-Environment-Variables
if [ -d "\$UPPM_HOME/installed/git/libexec/git-core" ] ; then
    export GIT_EXEC_PATH="\$UPPM_HOME/installed/git/libexec/git-core"
    export GIT_TEMPLATE_DIR="\$UPPM_HOME/installed/git/share/git-core/templates"
    export GIT_CONFIG_NOSYSTEM=1
fi
EOF

    if [ "$TERMUX" = 1 ] ; then
        cat >> init.sh <<EOF
TERMUX=1
export CURLOPT_DNS_SERVERS='8.8.8.8,1.1.1.1'
export UPPM_FORMULA_REPO_URL_OFFICIAL_CORE='$UPPM_FORMULA_REPO_URL_OFFICIAL_CORE'
EOF
    fi

    ##################################################################################

    run "$UPPM_HOME/installed/gsed/bin/gsed" -i "'s|NDKPKG_CORE_DIR|$NDKPKG_CORE_DIR|'" fonts.conf

    ##################################################################################

    if [ -d        "$NDKPKG_CORE_DIR" ] ; then
        run rm -rf "$NDKPKG_CORE_DIR"
    fi

    run mv "$SESSION_DIR" "$NDKPKG_HOME/"

    #################################################################################

    success "ndk-pkg-$NDKPKG_VERSION have been successfully setup."
}

__build_linux_headers() {
    export PATH="$PWD/bin:$PATH"

    LINUX_KERNAL_VERSION="$(cut -d ' ' -f3 < /proc/version | cut -d- -f1)"
    LINUX_KERNAL_VERSION="${LINUX_KERNAL_VERSION%.0}"
    LINUX_KERNAL_VERSION_MAJOR="${LINUX_KERNAL_VERSION%%.*}"
    LINUX_KERNAL_SRC_FILENAME="linux-$LINUX_KERNAL_VERSION.tar.xz"

    wfetch "https://cdn.kernel.org/pub/linux/kernel/v$LINUX_KERNAL_VERSION_MAJOR.x/$LINUX_KERNAL_SRC_FILENAME" --no-buffer

    run install -d linux-src
    run $TAR xf "$LINUX_KERNAL_SRC_FILENAME" -C linux-src --strip-components=1
    run cd linux-src
    run "$UPPM_HOME/installed/gmake/bin/gmake" headers_install INSTALL_HDR_PATH=../sysroot
    cd -
}

# }}}
##############################################################################
# {{{ ndk-pkg help

__help() {
    cat <<EOF
[38;5;204m    [38;5;198m    [38;5;199m   _ [38;5;163m_   [38;5;164m    [38;5;128m     [38;5;129m   _[38;5;93m    [38;5;99m     
[38;5;204m _ [38;5;198m__   [38;5;199m__| [38;5;163m| | [38;5;164m__   [38;5;128m  _ [38;5;129m__ |[38;5;93m | __[38;5;99m__ _[38;5;63m 
[38;5;204m| '[38;5;198m_ \ [38;5;199m/ _\` [38;5;163m| |/[38;5;164m /__[38;5;128m__| '[38;5;129m_ \|[38;5;93m |/ [38;5;99m/ _\` [38;5;63m|
[38;5;204m| |[38;5;198m | |[38;5;199m (_|[38;5;163m |   [38;5;164m<___[38;5;128m__| [38;5;129m|_) |[38;5;93m   <[38;5;99m (_|[38;5;63m |
[38;5;204m|_[38;5;198m| |_[38;5;199m|\__,[38;5;163m_|_|[38;5;164m\_\ [38;5;128m   | [38;5;129m.__/[38;5;93m|_|\_[38;5;99m\__,[38;5;63m |
[38;5;204m  [38;5;198m    [38;5;199m    [38;5;163m     [38;5;164m    [38;5;128m   |[38;5;129m_|   [38;5;93m    [38;5;99m |__[38;5;63m_/  $NDKPKG_VERSION
[0m
EOF

    printf '%b\n' "
${COLOR_GREEN}A package builder/manager for Android NDK to build projects written in C, C++, Rust, Golang, etc.${COLOR_OFF}

${COLOR_GREEN}ndk-pkg <ACTION> [ARGUMENT...]${COLOR_OFF}

${COLOR_GREEN}ndk-pkg --help${COLOR_OFF}
${COLOR_GREEN}ndk-pkg -h${COLOR_OFF}
    show help of this command.

${COLOR_GREEN}ndk-pkg --version${COLOR_OFF}
${COLOR_GREEN}ndk-pkg -V${COLOR_OFF}
    show version of this command.

${COLOR_GREEN}ndk-pkg setup [-y]${COLOR_OFF}
    install essential tools (e.g. uppm, bash, coreutils, findutils, gsed, gawk, grep, tree, git, curl, bsdtar, zip, xxd, fzf, bat, jq, yq, d2, pkg-config, patchelf, etc) used by this shell script.

    If -y is given, install curl via your system's package manager if none of curl wget http lynx aria2c axel command is found.

${COLOR_GREEN}ndk-pkg about${COLOR_OFF}
    show basic information about this software.

${COLOR_GREEN}ndk-pkg sysinfo${COLOR_OFF}
    show basic information about your current running operation system.

${COLOR_GREEN}ndk-pkg ndkinfo <ANDROID-NDK-HOME>${COLOR_OFF}
    show basic information about the specified location of Android NDK.

${COLOR_GREEN}ndk-pkg gen-url-transform-sample${COLOR_OFF}
    generate url-transform sample.

${COLOR_GREEN}ndk-pkg integrate zsh [--output-dir=<DIR>]${COLOR_OFF}
    download a zsh-completion script file to a approprivate location.

${COLOR_GREEN}ndk-pkg update${COLOR_OFF}
    update all the available formula repositories.

${COLOR_GREEN}ndk-pkg upgrade-self${COLOR_OFF}
    upgrade this software.

${COLOR_GREEN}ndk-pkg cleanup${COLOR_OFF}
    delete the unused cached files.


${COLOR_GREEN}ndk-pkg formula-repo-add  <FORMULA-REPO-NAME> <FORMULA-REPO-URL> [--branch=VALUE --pin/--unpin --enable/--disable --sync]${COLOR_OFF}
    create a new empty formula repository. If --sync option is given, sync with the server after the formula repo is created.

${COLOR_GREEN}ndk-pkg formula-repo-del  <FORMULA-REPO-NAME>${COLOR_OFF}
    delete the given formula repository.

${COLOR_GREEN}ndk-pkg formula-repo-sync <FORMULA-REPO-NAME>${COLOR_OFF}
    update the given formula repository.

${COLOR_GREEN}ndk-pkg formula-repo-info <FORMULA-REPO-NAME>${COLOR_OFF}
    show information of the given formula repository.

${COLOR_GREEN}ndk-pkg formula-repo-conf <FORMULA-REPO-NAME> [--url=VALUE --branch=VALUE --pin/--unpin --enable/--disable]${COLOR_OFF}
    change the config of the given formula repository.

${COLOR_GREEN}ndk-pkg formula-repo-list${COLOR_OFF}
    list all available formula repositories.


${COLOR_GREEN}ndk-pkg info-available <PACKAGE-NAME> [--json | --yaml | <KEY>]${COLOR_OFF}
    show information of the given available package.

${COLOR_GREEN}ndk-pkg info-installed <PACKAGE-SPEC> [--json | --yaml | <KEY>]${COLOR_OFF}
    show information of the given installed package.


${COLOR_GREEN}ndk-pkg ls-available [-v] [--json | --yaml]${COLOR_OFF}
    list all the available packages.

${COLOR_GREEN}ndk-pkg ls-installed${COLOR_OFF}
    list all the installed packages.

${COLOR_GREEN}ndk-pkg ls-outdated${COLOR_OFF}
    list all the outdated  packages.


${COLOR_GREEN}ndk-pkg is-available <PACKAGE-NAME>${COLOR_OFF}
    check if the given package is available.

${COLOR_GREEN}ndk-pkg is-installed <PACKAGE-SPEC>${COLOR_OFF}
    check if the given package is installed.

${COLOR_GREEN}ndk-pkg is-outdated  <PACKAGE-SPEC>${COLOR_OFF}
    check if the given package is outdated.


${COLOR_GREEN}ndk-pkg search <REGULAR-EXPRESSION-PATTERN> [-v]${COLOR_OFF}
    search all available packages whose name matches the given regular expression pattern.


${COLOR_GREEN}ndk-pkg depends <PACKAGE-NAME> [-t <OUTPUT-TYPE>] [-o <OUTPUT-PATH>] [--engine=<d2|dot>]${COLOR_OFF}
    show the packages that are depended by the given package.

    <OUTPUT-TYPE> must be any one of d2 dot box svg png

    <OUTPUT-PATH> can be either the filepath or directory.

    If <OUTPUT-PATH> is . .. or ends with slash(/), then it will be treated as a directory, otherwise, it will be treated as a filepath.

    If <OUTPUT-PATH> is treated as a directory, then it will be expanded to <OUTPUT-PATH>/<PACKAGE-NAME>-dependencies.<OUTPUT-TYPE>

    If -o <OUTPUT-PATH> option is unspecified, the result will be written to stdout.

    If -t <OUTPUT-TYPE> option is unspecified, and if <OUTPUT-PATH> ends with one of .d2 .dot .box .svg .png, <OUTPUT-TYPE> will be the <OUTPUT-PATH> suffix, otherwise, <OUTPUT-TYPE> will be box.

    You are allowd to choose the diagram engine for generating svg/png format diagram. ndk-pkg only support d2 and dot diagram engine at the moment.


${COLOR_GREEN}ndk-pkg fetch <PACKAGE-NAME>${COLOR_OFF}
    download all the resources of the given package to the local cache.


${COLOR_GREEN}ndk-pkg install [android-<ANDROID-API>-<ANDROID-ABIs>/]<PACKAGE-NAME>... [INSTALL-OPTIONS]${COLOR_OFF}
    install the given packages.

    ${COLOR_RED}<ANDROID-ABIs>${COLOR_OFF} is a comma-separated list, any combination of arm64-v8a, armeabi-v7a, x86_64, x86

    INSTALL-OPTIONS:
        ${COLOR_BLUE}--target=android-<ANDROID-API>-<ANDROID-ABI>${COLOR_OFF}
            specify the target to be built for.

            If this option is unspecified, the environment variable ${COLOR_RED}NDKPKG_DEFAULT_TARGET${COLOR_OFF} is honored, if the environment variable NDKPKG_DEFAULT_TARGET is not set, then android-21-arm64-v8a will be used as the default.

        ${COLOR_BLUE}--ndk-home=<ANDROID-NDK-HOME>${COLOR_OFF}
            use the specified location of Android NDK.

            If you want to use your own installed Android NDK, use this option.

        ${COLOR_BLUE}--ndk-revision=<ANDROID-NDK-REVISION>${COLOR_OFF}
            use the specified revision of Android NDK.

            <ANDROID-NDK-REVISION> can be 28c, 27d, 26d, 25c, etc. Please visit https://developer.android.com/ndk/downloads/revision_history for more details on Android NDK revsion.

            If the specified revision of Android NDK isn't installed, it will be automatically installed for you via uppm.

            If neither --ndk-home=<ANDROID-NDK-HOME> nor --ndk-revision=<ANDROID-NDK-REVISION> is specified, a proper revision of Android NDK will be automatically installed for you via uppm.

            --ndk-home=<ANDROID-NDK-HOME> and --ndk-revision=<ANDROID-NDK-REVISION> options are mutually exclusive. You can only specify one of them.

        ${COLOR_BLUE}--profile=<debug|release>${COLOR_OFF}
            specify the build profile.

            debug:
                  CFLAGS: -O0 -g
                CXXFLAGS: -O0 -g

            release:
                  CFLAGS: -Os
                CXXFLAGS: -Os
                CPPFLAGS: -DNDEBUG
                 LDFLAGS: -flto -Wl,-s

        ${COLOR_BLUE}--static${COLOR_OFF}
            create Fully Statically Linked Executables

            This option only affects the package whose type is exe. If this option is not given, ndk-pkg will create Mostly Statically Linked Executables

            a  fully statically linked executable is a executable that without any additional libraries to be loaded at runtime.
            a mostly statically linked executable is a executable that without any additional libraries except libc.so, libm.so, libdl.so, liblog.so, etc.

            a fully  statically linked executable is easy to distribute to all version of Android devices.
            a mostly statically linked executable is easy to distribute to one version of Android devices.

        ${COLOR_BLUE}-j <N>${COLOR_OFF}
            specify the max number of jobs you could run in parallel.

        ${COLOR_BLUE}-I <FORMULA-SEARCH-DIR>${COLOR_OFF}
            specify the formula search directory. This option can be used multiple times.

        ${COLOR_BLUE}-E${COLOR_OFF}
            export compile_commands.json

        ${COLOR_BLUE}-U${COLOR_OFF}
            upgrade packages if possible.

        ${COLOR_BLUE}-K${COLOR_OFF}
            keep the session directory even if this package is successfully installed.

        ${COLOR_BLUE}-q${COLOR_OFF}
            silent mode. no any messages will be output to terminal.

        ${COLOR_BLUE}-v${COLOR_OFF}
            verbose mode. many messages will be output to terminal.

            This option is equivalent to -v-* options all are supplied.

        ${COLOR_BLUE}-x${COLOR_OFF}
            very verbose mode. many many messages will be output to terminal.

            This option is equivalent to -v-* and -x-* options all are supplied.

        ${COLOR_BLUE}-v-env${COLOR_OFF}
            show all environment variables before starting to build.

        ${COLOR_BLUE}-v-http${COLOR_OFF}
            show http request/response.

        ${COLOR_BLUE}-v-ndk${COLOR_OFF}
            show Android NDK information.

        ${COLOR_BLUE}-v-formula${COLOR_OFF}
            show formula content.

        ${COLOR_BLUE}-v-go${COLOR_OFF}
            pass -v argument to go build command.

        ${COLOR_BLUE}-v-uppm${COLOR_OFF}
            pass -v argument to uppm command.

        ${COLOR_BLUE}-v-cargo${COLOR_OFF}
            pass -v argument to cargo command.

        ${COLOR_BLUE}-v-meson${COLOR_OFF}
            pass -v argument to meson command.

        ${COLOR_BLUE}-v-ninja${COLOR_OFF}
            pass -v argument to ninja command.

        ${COLOR_BLUE}-v-gmake${COLOR_OFF}
            pass V=1 argument to gmake command.

        ${COLOR_BLUE}-v-cmake${COLOR_OFF}
            set(CMAKE_VERBOSE_MAKEFILE ON)

        ${COLOR_BLUE}-v-xmake${COLOR_OFF}
            pass -v argument to xmake command.

        ${COLOR_BLUE}-x-sh${COLOR_OFF}
            set -x to debug current running shell.

        ${COLOR_BLUE}-x-cc${COLOR_OFF}
            pass -v argument to clang command.

        ${COLOR_BLUE}-x-ld${COLOR_OFF}
            pass -Wl,-v argument to linker.

        ${COLOR_BLUE}-x-go${COLOR_OFF}
            pass -x argument to go build command.

        ${COLOR_BLUE}-x-cargo${COLOR_OFF}
            pass -vv argument to cargo command.

        ${COLOR_BLUE}-x-gmake${COLOR_OFF}
            pass --debug argument to gmake command.

        ${COLOR_BLUE}-x-cmake${COLOR_OFF}
            set(CMAKE_FIND_DEBUG_MODE ON)

        ${COLOR_BLUE}-x-xmake${COLOR_OFF}
            pass -vD argument to xmake command.

        ${COLOR_BLUE}-x-pkg-config${COLOR_OFF}
            export PKG_CONFIG_DEBUG_SPEW=1

        ${COLOR_BLUE}--disable-ccache${COLOR_OFF}
            do not use ccache.

    USAGE-EXAMPLES:
        ndk-pkg install android-21-arm64-v8a/libz
        ndk-pkg install android-21-arm64-v8a,armeabi-v7a/libz
        ndk-pkg install android-21-arm64-v8a,armeabi-v7a,x86_64/libz
        ndk-pkg install android-21-arm64-v8a,armeabi-v7a,x86_64,x86/libz

${COLOR_GREEN}ndk-pkg reinstall android-<ANDROID-API>-<ANDROID-ABIs>/<PACKAGE-NAME>... [INSTALL-OPTIONS]${COLOR_OFF}
    reinstall the given packages.

${COLOR_GREEN}ndk-pkg upgrade   android-<ANDROID-API>-<ANDROID-ABIs>/<PACKAGE-NAME>... [INSTALL-OPTIONS]${COLOR_OFF}
    upgrade the given packages or all outdated packages.

${COLOR_GREEN}ndk-pkg uninstall <PACKAGE_SPEC>...${COLOR_OFF}
    uninstall the given packages.


${COLOR_GREEN}ndk-pkg tree <PACKAGE-SPEC> [--dirsfirst | -L N]${COLOR_OFF}
    list the installed files of the given installed package in a tree-like format.

${COLOR_GREEN}ndk-pkg logs <PACKAGE-SPEC>${COLOR_OFF}
    show logs of the given installed package.

    This will launch fzf finder. press ESC key to quit.


${COLOR_GREEN}ndk-pkg bundle <PACKAGE-SPEC> [<OUTPUT-DIR>][<OUTPUT-FILENAME-PREFIX>]<BUNDLE-TYPE> [--exclude <PATH>] [-K]${COLOR_OFF}
    bundle the given installed package into a single archive file.

    ${COLOR_BLUE}<OUTPUT-DIR>${COLOR_OFF}
        If specified, should end with slash.

    ${COLOR_BLUE}<OUTPUT-FILENAME-PREFIX>${COLOR_OFF}
        If unspecified, use <PACKAGE-NAME>-<PACKAGE-VERSION>-<TARGET-PLATFORM-NAME>-<TARGET-PLATFORM-VERSION>-<TARGET-PLATFORM-ARCH> as default.

    ${COLOR_BLUE}<BUNDLE-TYPE>${COLOR_OFF}
        should be any one of .tar.gz .tar.xz .tar.lz .tar.bz2 .zip

    ${COLOR_BLUE}--exclude <PATH>${COLOR_OFF}
        exclude file that is not mean to be bundled into the final file.

        <PATH> is relative to the installed root directory.

        this option can be used multiple times.

    ${COLOR_BLUE}-K${COLOR_OFF}
        keep the session directory even if this package is successfully bundled.


${COLOR_GREEN}ndk-pkg export android-<ANDROID-API>-<ANDROID-ABIs>/<PACKAGE-NAME> [OPTIONS]${COLOR_OFF}
    export the given installed package as google prefab aar.

    For details about google prefab, please visit https://google.github.io/prefab/

    For details about the aar file contains google prefab, please visit https://developer.android.com/studio/projects/android-library#aar-contents

    ${COLOR_BLUE}<ANDROID-ABIs>${COLOR_OFF}
        A comma-separated list, any combination of arm64-v8a, armeabi-v7a, x86_64, x86

    ${COLOR_BLUE}--ndk-home=<ANDROID-NDK-HOME>${COLOR_OFF}
        If this option is unspecified, a proper version of Android NDK will be automatically installed for you via uppm.

    ${COLOR_BLUE}-o <OUTPUT-PATH>${COLOR_OFF}
        specify where the aar file will be written to.

        <OUTPUT-PATH> can be either the filepath or directory.

        If <OUTPUT-PATH> is an existing directory or ends with slash, then it will be treated as a directory, otherwise, it will be treated as a filepath.

        If <OUTPUT-PATH> is treated as a directory, then it would be expanded to <OUTPUT-PATH>/<PACKAGE-NAME>-<PACKAGE-VERSION>.aar

    ${COLOR_BLUE}-K${COLOR_OFF}
        keep the session directory even if this package is successfully exported.

${COLOR_GREEN}ndk-pkg deploy android-<ANDROID-API>-<ANDROID-ABIs>/<PACKAGE-NAME> [OPTIONS]${COLOR_OFF}
    export the given installed package as google prefab aar then deploy it to Maven Repository.

    For details about google prefab, please visit https://google.github.io/prefab/

    For details about the aar file contains google prefab, please visit https://developer.android.com/studio/projects/android-library#aar-contents

    ${COLOR_BLUE}<ANDROID-ABIs>${COLOR_OFF}
        A comma-separated list, any combination of arm64-v8a, armeabi-v7a, x86_64, x86

    ${COLOR_BLUE}--ndk-home=<ANDROID-NDK-HOME>${COLOR_OFF}
        If this option is unspecified, a proper version of Android NDK will be automatically installed for you via uppm.

    ${COLOR_BLUE}--debug${COLOR_OFF}
        pass -X option to mvn command.

    ${COLOR_BLUE}--dry-run${COLOR_OFF}
        just bundle the aar file, do not actually export.

    ${COLOR_BLUE}-K${COLOR_OFF}
        keep the session directory even if this package is successfully exported.

    ${COLOR_BLUE}--groupId=<GROUPID>${COLOR_OFF}
        specify the groupId.

        If this option is unspecified, ${COLOR_RED}com.fpliu.ndk.pkg.prefab.android.<ANDROID-API>${COLOR_OFF} would be used as default.

    ${COLOR_BLUE}--local=<DIR>${COLOR_OFF}
        deploy the aar file to the specified location of Maven Local Repository.

    ${COLOR_BLUE}--remote${COLOR_OFF}
        deploy the aar file to Sonatype OSSRH (https://s01.oss.sonatype.org/)

        If this option is specified, some extra information would be read from stdin. stdin should contain the following content:

        SERVER_ID=
        SERVER_URL=
        SERVER_USERNAME=
        SERVER_PASSWORD=
        GPG_PASSPHRASE=

    ${COLOR_RED}Caveat:${COLOR_OFF} If neither --local=<DIR> nor --remote is specified, the aar file would be deployed to your default Maven Local Repository (usually under ~/.m2/repository/ directory, depending on your settings.xml configuration)


==================
Naming explanation
==================

${COLOR_GREEN}<PACKAGE-SPEC>${COLOR_OFF}
    a formatted string that has form: ${COLOR_RED}<TARGET>/<PACKAGE-NAME>${COLOR_OFF}, represents an installed package.

${COLOR_GREEN}<PACKAGE-NAME>${COLOR_OFF}
    must match the regular expression pattern ${COLOR_RED}^[A-Za-z0-9+-_.@]{1,50}\$${COLOR_OFF}

${COLOR_GREEN}<TARGET>${COLOR_OFF}
    a formatted string that has form: ${COLOR_RED}android-<ANDROID-API>-<ANDROID-ABI>${COLOR_OFF}

${COLOR_GREEN}<ANDROID-API>${COLOR_OFF}
    indicates which minimum Android SDK API level was built with.

    Reference: https://developer.android.com/tools/releases/platforms

${COLOR_GREEN}<ANDROID-ABI>${COLOR_OFF}
    indicates which Android ABI was built for.

    Reference: https://developer.android.com/ndk/guides/abis


=====================
Environment variables
=====================

${COLOR_GREEN}HOME${COLOR_OFF}
    This environment variable already have been set on the most operating systems, if not set or set a empty string, you may receive an error message.

${COLOR_GREEN}PATH${COLOR_OFF}
    This environment variable already have been set on the most operating systems, if not set or set a empty string, you may receive an error message.

${COLOR_GREEN}SSL_CERT_FILE${COLOR_OFF}
    In general, you don't need to set this environment variable, but, if you encounter the reporting ${COLOR_RED}the SSL certificate is invalid${COLOR_OFF}, trying to run below commands in your terminal will do the trick.

    ${COLOR_RED}curl -LO https://curl.se/ca/cacert.pem
    export SSL_CERT_FILE="\$PWD/cacert.pem"${COLOR_OFF}

${COLOR_GREEN}GOPROXY${COLOR_OFF}
    Example:

    ${COLOR_RED}export GOPROXY='https://goproxy.cn'${COLOR_OFF}

${COLOR_GREEN}NDKPKG_HOME${COLOR_OFF}
    ndk-pkg would generate all data under ${COLOR_RED}~/.ndk-pkg${COLOR_OFF} directory by default, you could change it by setting this environment variable.

    Example:

    ${COLOR_RED}export NDKPKG_HOME=/path/of/ndk-pkg-home${COLOR_OFF}

${COLOR_GREEN}NDKPKG_URL_TRANSFORM${COLOR_OFF}
    If you want to change the request url, you can set this environment variable. It is very useful for chinese users.

    Example:

    ${COLOR_RED}export NDKPKG_URL_TRANSFORM=/path/of/url-transform${COLOR_OFF}

    /path/of/url-transform command would be invoked as /path/of/url-transform <URL>

    /path/of/url-transform command must output a <URL>

    a url-transform sample can be generated via running ${COLOR_RED}ndk-pkg gen-url-transform-sample${COLOR_OFF}

${COLOR_GREEN}NDKPKG_XTRACE${COLOR_OFF}
    for debugging purposes. to enable set -x: ${COLOR_RED}export NDKPKG_XTRACE=1${COLOR_OFF}

${COLOR_GREEN}NDKPKG_DEFAULT_TARGET${COLOR_OFF}
    some ACTIONs of ndk-pkg need <PACKAGE-SPEC> to be specified. To simplify the usage, you are allowed to omit <TARGET>/. If <TARGET>/ is omitted, environment variable NDKPKG_DEFAULT_TARGET would be checked, if it is not set, then ${COLOR_RED}android-21-aarm64-v8a${COLOR_OFF} will be used as the default.

    Example:

    ${COLOR_RED}export NDKPKG_DEFAULT_TARGET='android-21-arm64-v8a'${COLOR_OFF}


=======
Caveats
=======

This software is being actively developed. It's in beta stage and may not be stable. Some features are subject to change without notice.

Please do NOT place your own files under ~/.ndk-pkg directory, as ndk-pkg will change files under ~/.ndk-pkg directory without notice.

Please do NOT run ndk-pkg command in parallel so as not to generate dirty data.
    "

    if [ -z "$1" ] ; then
        exit
    else
        exit "$1"
    fi
}

# }}}
##############################################################################
# {{{ ndk-pkg main

set -e

# If IFS is not set, the default value will be <space><tab><newline>
# https://pubs.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html#tag_18_05_03
unset IFS

##################################################################################

if [ -n "$NDKPKG_XTRACE" ] ; then
    set -x
fi

[ -z "$NDKPKG_HOME" ] && {
    if [ -z "$HOME" ] ; then
        abort 1 "HOME environment variable is not set."
    else
        export NDKPKG_HOME="$HOME/.ndk-pkg"
    fi
}

NDKPKG_VERSION=0.26.1

NDKPKG_ARG0="$0"
NDKPKG_ARG1="$1"
NDKPKG_ARGV="$0 $*"

NDKPKG_PATH="$(cd "$(dirname "$0")" && pwd)/$(basename "$0")"

NDKPKG_ZSH_COMPLETION_SCRIPT_URL='https://raw.githubusercontent.com/leleliu008/ndk-pkg/master/ndk-pkg-zsh-completion'
NDKPKG_OFFICIAL_FORMULA_REPO_URL='https://github.com/leleliu008/ndk-pkg-formula-repository-official-core.git'
NDKPKG_UPGRAGE_URL='https://raw.githubusercontent.com/leleliu008/ndk-pkg/master/ndk-pkg'

NDKPKG_CORE_DIR="$NDKPKG_HOME/core"

NDKPKG_DOWNLOADS_DIR="$NDKPKG_HOME/downloads"

NDKPKG_FORMULA_REPO_ROOT="$NDKPKG_HOME/repos.d"

NDKPKG_PACKAGE_INSTALLED_ROOT="$NDKPKG_HOME/installed"

##################################################################################

NATIVE_PACKAGE_INSTALLED_ROOT="$NDKPKG_HOME/native"

##################################################################################

UPPM="$NDKPKG_CORE_DIR/uppm"

export UPPM_HOME="$NDKPKG_HOME/uppm"

uppm() {
    if [ "$1" = install ] ; then
        if [ "$DUMP_UPPM" = 1 ] ; then
            run "$UPPM" "$@" -v
        else
            run "$UPPM" "$@"
        fi
    else
            run "$UPPM" "$@"
    fi
}

if [ -n "$NDKPKG_URL_TRANSFORM" ] ; then
    export  UPPM_URL_TRANSFORM="$NDKPKG_URL_TRANSFORM"
    export       URL_TRANSFORM="$NDKPKG_URL_TRANSFORM"
fi

##################################################################################

# https://www.openssl.org/docs/man1.1.1/man3/SSL_CTX_set_default_verify_paths.html
if [ -f "$NDKPKG_CORE_DIR/cacert.pem" ] ; then
    export SSL_CERT_FILE="$NDKPKG_CORE_DIR/cacert.pem"
fi

##################################################################################

# dot_static command use this
# https://www.freedesktop.org/software/fontconfig/fontconfig-user.html
if [ -z  "$FONTCONFIG_FILE" ] ; then
    export FONTCONFIG_FILE="$NDKPKG_CORE_DIR/fonts.conf"
fi

##################################################################################

TIMESTAMP_UNIX="$(date +%s)"

##################################################################################

export BAT_THEME=Dracula

unset TERMUX

##################################################################################

case $1 in
    ''|--help|-h)
        __help
        exit
        ;;
    --version|-V)
        printf '%s\n' "$NDKPKG_VERSION"
        exit
        ;;
    about)
        if command -v bat > /dev/null ; then
            VIEWER='bat --language=yaml --paging=never --color=always --theme=Dracula --style=plain'
        else
            VIEWER=cat
        fi

        $VIEWER <<EOF
ndk-pkg.version: $NDKPKG_VERSION
ndk-pkg.homedir: $NDKPKG_HOME
ndk-pkg.exepath: $NDKPKG_PATH
ndk-pkg.website: https://github.com/leleliu008/ndk-pkg
EOF
        if [ -f "$UPPM" ] ; then
            printf '\n'
            "$UPPM" about
        fi

        exit
        ;;
    setup)
        shift
        __setup "$@"
        exit
        ;;
    gen-url-transform-sample)
        shift
        __gen_url_transform_sample "$@"
        exit
        ;;
    android-versions)
        # https://apilevels.com/
        cat <<EOF
Android 15          35  VANILLA_ICE_CREAM
Android 14          34  UPSIDE_DOWN_CAKE
Android 13          33  TIRAMISU
Android 12          32  S_V2
Android 12          31  S
Android 11          30  R
Android 10          29  Q
Android 9           28  P
Android 8.1         27  O_MR1
Android 8.0         26  O
Android 7.1         25  N_MR1
Android 7.0         24  N
Android 6.0         23  M
Android 5.1         22  LOLLIPOP_MR1
Android 5.0         21  LOLLIPOP
Android 4.4W        20  KITKAT_WATCH
Android 4.4         19  KITKAT
Android 4.3         18  JELLY_BEAN_MR2
Android 4.2         17  JELLY_BEAN_MR1
Android 4.1         16  JELLY_BEAN
Android 4.0.3,4     15  ICE_CREAM_SANDWICH_MR1
Android 4.0,.1,.2   14  ICE_CREAM_SANDWICH
Android 3.2         13  HONEYCOMB_MR2
Android 3.1.x       12  HONEYCOMB_MR1
Android 3.0.x       11  HONEYCOMB
Android 2.3.3,.4    10  GINGERBREAD_MR1
Android 2.3,.1,.2   9   GINGERBREAD
Android 2.2.x       8   FROYO
Android 2.1.x       7   ECLAIR_MR1
Android 2.0.1       6   ECLAIR_0_1
Android 2.0         5   ECLAIR
Android 1.6         4   DONUT
Android 1.5         3   CUPCAKE
Android 1.1         2   BASE_1_1
Android 1.0         1   BASE
EOF
        exit
        ;;
esac

##################################################################################

[ -z  "$CARGO_HOME" ] && {
    if [ -z "$HOME" ] ; then
        abort 1 "HOME environment variable is not set."
    else
        CARGO_HOME="$HOME/.cargo"
    fi
}

bppend_to_PATH "$CARGO_HOME/bin"

##################################################################################

if [ -d         "$NDKPKG_CORE_DIR/bin" ] ; then
    export PATH="$NDKPKG_CORE_DIR/bin:$PATH"
fi

##################################################################################

if [ -f "$NDKPKG_CORE_DIR/init.sh" ] ; then
    .   "$NDKPKG_CORE_DIR/init.sh"
else
    abort 1 "please run ${COLOR_GREEN}$NDKPKG_ARG0 setup${COLOR_OFF} command first, then try again."
fi

##################################################################################

# https://www.gnu.org/software/automake/manual/html_node/Macro-Search-Path.html
if [ -z  "$ACLOCAL_PATH" ] ; then
    export ACLOCAL_PATH="$NDKPKG_CORE_DIR/share/aclocal"
else
    export ACLOCAL_PATH="$NDKPKG_CORE_DIR/share/aclocal:$ACLOCAL_PATH"
fi

##################################################################################

unset NATIVE_PLATFORM_KIND
unset NATIVE_PLATFORM_TYPE
unset NATIVE_PLATFORM_CODE
unset NATIVE_PLATFORM_NAME
unset NATIVE_PLATFORM_VERS
unset NATIVE_PLATFORM_ARCH
unset NATIVE_PLATFORM_NCPU
unset NATIVE_PLATFORM_LIBC
unset NATIVE_PLATFORM_EUID
unset NATIVE_PLATFORM_EGID

eval "$("$UPPM" sysinfo --shell)"

if [ "$NATIVE_PLATFORM_KIND" = darwin ] ; then
    case $NATIVE_PLATFORM_VERS in
        1[5-9].*) export UPPM_FORMULA_REPO_URL_OFFICIAL_CORE="https://github.com/leleliu008/uppm-package-repository-macos-15.0-$NATIVE_PLATFORM_ARCH"
    esac
fi

##################################################################################

if [ "$NATIVE_PLATFORM_EUID" -ne 0 ] ; then
    sudo=sudo
fi

##################################################################################

case $1 in
    ndkinfo)
        shift
        inspect_android_ndk_info "$1"
        println_android_ndk_info
        ;;

    sysinfo)
        shift
        "$UPPM" sysinfo "$@"
        ;;

    update)            shift; __sync_available_formula_repositories "$@" ;;
    formula-repo-list) shift; __list_available_formula_repositories "$@" ;;
    formula-repo-info) shift; __info_the_given_formula_repository "$@" ;;
    formula-repo-conf) shift; __conf_the_given_formula_repository "$@" ;;
    formula-repo-sync) shift; __sync_the_given_formula_repository "$@" ;;
    formula-repo-add)
        shift

        case $1 in
            official-*) abort 1 "ndk-pkg formula repository name that starts with 'official-' is reserved for ndk-pkg official formula repository, please use other name."
        esac

        __create_a_formula_repository "$@"
        ;;
    formula-repo-del)
        shift
        __delete_a_formula_repository "$@"
        ;;

    info-available) shift; __info_the_given_available_package "$@" ;;
    info-installed) shift; __info_the_given_installed_package "$@" ;;

    ls-available) shift; __list_available_packages "$@" ;;
    ls-installed) shift; __list_installed_packages "$@" ;;
    ls-outdated)  shift; __list__outdated_packages "$@" ;;

    is-available) shift; is_package_available "$@" ;;

    is-installed)
        shift
        PACKAGE_SPEC=
        PACKAGE_SPEC="$(inspect_package_spec "$1")"
        is_package_installed "$PACKAGE_SPEC"
        ;;

    is-outdated)
        shift
        PACKAGE_SPEC=
        PACKAGE_SPEC="$(inspect_package_spec "$1")"
        is_package__outdated "$PACKAGE_SPEC"
        ;;

    search)  shift; __search_packages "$@" ;;

    depends) shift; __show_packages_depended_by_the_given_package "$@" ;;
    fetch)   shift;        __fetch_resources_of_the_given_package "$@" ;;

    install) shift;   __install_the_given_packages "$@" ;;
  reinstall) shift; __reinstall_the_given_packages "$@" ;;
  uninstall) shift; __uninstall_the_given_packages "$@" ;;

    upgrade) shift; __upgrade_packages "$@" ;;

    upgrade-self)
             shift; __upgrade_self "$NDKPKG_UPGRAGE_URL" "$@" ;;

    logs)   shift; __logs_the_given_installed_package "$@" ;;
    tree)   shift; __tree_the_given_installed_package "$@" ;;
    bundle) shift; __bundle_the_given_installed_package "$@" ;;

    export) shift; __export_google_prefab_aar_for_the_given_installed_packages "$@" ;;
    deploy) shift; __deploy_google_prefab_aar_for_the_given_installed_packages "$@" ;;

    integrate)
        shift
        case $1 in
            zsh)
                shift
                __integrate_zsh_completions "$NDKPKG_ZSH_COMPLETION_SCRIPT_URL" "$@"
                ;;
            *)  abort 1 "ndk-pkg integrate $1: not support."
        esac
        ;;

    cleanup) shift; __cleanup ;;

    run)
        shift

        case $1 in
            uppm) shift; "$UPPM" "$@" ;;
            '')   abort 1 'no command is supplied to run.' ;;
            *)    "$@"
        esac
        ;;

    *)  abort 1 "unrecognized argument: $1"
esac

# }}}
